模块设计是否良好,有个重要的因素在于,相对外部模块是否隐藏内部数据以及实现细节。
设计良好的模块会隐藏实现细节,并将API与其实现隔离开来。
模块之间通过API进行通信,对于内部工作情况互不可见。
即,封装(encapsulation)——软件设计的基本原则之一。

为什么要封装?
通过封装可以有效地接触各个模块之间的耦合关系,使这些模块可以独立地开发、测试、优化、使用、理解和修改。
即:

  • 可以增加开发效率,模块可以并行开发。
  • 封装可以减轻维护的负担,可以更有效的进行优化,且不会影响其他模块的正确性。
  • 提高了软件的可重用性,模块在其他环境中也可以被使用。

(PS:回想我自己以前用php写网站时根本没有这些概念也不影响开发工作。当时觉得没什么,因为是我一个人写的,再加上后来也没有再扩展,于是没有了种种体会。)

可以通过访问控制保证封装。
一个实体的可访问性是通过实体声明所在的位置和访问修饰符共同决定的。
建议尽可能地使每个类或者成员不被外界访问

对于顶层的类和接口只有两种访问级别:包级私有公有
更小的可访问性代表更小的兼容性,在以后发行的版本中可以放心对其进行修改。
如果是公有的,则需要一直考虑客户的行为。(PS:如果一个顶层类只是在某一个类的内部被用到,则可以声明为私有静态内部类。)
比如这样一个类,这样做在以后的版本中便无法改变表示方式,而且无法加入任何约束:

class Point {
public double x;
public double y;
}

于是正如很多人的习惯那样,对于公有类用公有的访问方法替代公有field以保证数据在类内部的灵活性:
class Point {
private double x;
private double y;

    public Point(double x, double y) {
this.x = x;
this.y = y;
} public double getX() {
return x;
} public double getY() {
return y;
} public void setX(double x) {
this.x = x;
} public void setY(double y) {
this.y = y;
}
}

(PS:当然,有些常见的类并没有遵守这一规则比如java.awt.Point、java.awt.Dimension。
但原作者也明确指出这些类不值得效仿。)

如果一个field只能是公有的,且允许将其声明为final,则危害能少一些。
我们仍然可以通过公有的访问方法访问该field。
但不能用公有的setter,而是通过构造器加入约束:

public final class Time {
private static final int HOURS_PER_DAY = 24;
private static final int MINUTES_PER_HOUR = 60; public final int hour;
public final int minute; public Time(int hour, int minute) {
if (hour < 0 || hour >= HOURS_PER_DAY)
throw new IllegalArgumentException("Hour: " + hour);
if (minute < 0 || minute >= MINUTES_PER_HOUR)
throw new IllegalArgumentException("Min: " + minute);
this.hour = hour;
this.minute = minute;
}
// Remainder omitted
}

对于成员(field,method,嵌套类,嵌套接口)有4种访问级别:

  • private
  • package-private(default)
  • protected
  • public

当设计了类的公有API后,我们将所有成员都变成私有。
然后发现同一个包内的另一个类也需要访问这个成员,于是便修改访问级别。如果这种事情经常发生则应该检查设计是否合理。
虽然package和private级别的成员都是类实现的一部分,不会影响导出的API。
但,该类实现了Serializable时则另当别论。
如果使用protected修饰,则需要注意,该成员时导出的API的一部分。

另外,实例field尽量不要设置为公有。如果一个field不是final或者是一个指向可变对象的final field,公有的访问级别会破坏该field的不可变性,它已不是一个内部的数据表示,而且非线程安全。
当然,这对于长度!=0的数组也是一样的。

如果需要将某数组声明为公有,可以尝试以下方式:

private static final Thing[] PRIVATE_VALUES = {...};
public static final List<Thing> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));

或者可以使用clone,每次都拷贝一个数组:

private static final Thing[] PRIVATE_VALUES = {...};
public static final Thing[] values(){
return PRIVATE_VALUES.clone();
}

Java - 使可访问性最小化的更多相关文章

  1. 《Effective Java》笔记 使类和成员的可访问性最小化

    类和接口 第13条 使类和成员的可访问性最小化 1.设计良好的模块会隐藏所有的实现细节,把它的API与实现清晰的隔离开来,模块之间只通过它们的API进行通信,一个模块不需要知道其他模块的内部工作情况: ...

  2. Effective Java 第三版——15. 使类和成员的可访问性最小化

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  3. EffectiveJava(13)使类和成员的可访问性最小化

    1.为什么要使类和成员可访问性最小化 它可以有效地解除组成系统的各模块之间的耦合关系,使得这些模块可以独立的开发 测试 优化 使用 理解和修改.提高软件的可重用性 2.成员的访问级别 私有(priva ...

  4. Effective Java —— 使类和成员的可访问性最小化

    本文参考 本篇文章参考自<Effective Java>第三版第十五条"Minimize the accessibility of classes and members&quo ...

  5. Effective Java --使类和成员的可访问性最小化

    尽可能地降低可访问性 接口和成员变量访问级别四种访问级别: 私有的(private) --- 只有在生命该成员的顶层类内部才可以访问 包级私有的(package-private) --- 缺省的&qu ...

  6. Effective Java:Ch4_Class:Item13_最小化类及其成员的可访问性

    要区别一个模块是否设计良好,最重要的因素是,对于其他模块而言该模块隐藏其内部数据和其他实现细节的程度.设计良好的模块应该隐藏所有实现细节,将API与其实现清晰地隔离开来.这样,模块之间通过他们的API ...

  7. Effective Java 第三版——17. 最小化可变性

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  8. Effective Java 第三版——57. 最小化局部变量的作用域

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  9. VC++ 如何使窗体最大化或是最小化

    最大化最小的使得的函数是 ShowWindow函数 ShowWindow(SW_SHOWMINIMIZED);//最小化 ShowWindow(SW_SHOWMAXIMIZED);//最大化 Show ...

随机推荐

  1. python--变量,常量,用户交互

    1.变量 概念:把程序运行过程中产生的中间值保存在内存,方便后面使用 命名规范: 1.字母,数字,下划线组成 2.不能用数字开头,且不能用纯数字 3.不能用python关键字 4.不要用中文 5.要有 ...

  2. Redis Sentinel初体验

        自Redis增加Sentinel集群工具以来,本博主就从未尝试过使用该工具.最近在调研目前主流的Redis集群部署方案,所以详细地看了一遍官方对于Sentinel的介绍并在自己的台式机上完成了 ...

  3. oracle常用cmd命令

    登陆 sqlplus username/password; 切换: conn username/password; 显示当前登陆用户: show user; 查看用户列表 select usernam ...

  4. GitHub创建项目,保存代码。

    平时学习会写一些代码,虽然只是零零散散的功能,但是基本都是在一个项目下操作,偶尔会忘记代码编辑顺序.国庆这几天在家,想把GitHub用起来,实现自己代码的可追溯,可查询.学习本篇博客,你需要一点的Gi ...

  5. 微信小程序ofo小黄车+thinkphp5.0打造全栈应用

    原文地址:https://www.imooc.com/article/20310 ofo至今还没有微信小程序(很费解),每次用ofo都得去支付宝,很不方便,我用微信用的比较多,无意间在简书上面看到某人 ...

  6. 总结day7 ---- 函数的内容 ,初识,返回值,进阶(一)

    内容大纲: 一: 函数识别 二: 函数的结构 三: 函数的返回值, 四: 函数的参数 五: 动态参数 六: 形参的顺序 七: 名称空间 八: 作用域 九: 加载顺序和取值顺序 十: 内置函数 十一: ...

  7. 2019年北航OO第二次博客总结

    一.多线程电梯系列作业设计策略 1. 第一次作业——"FAFS傻瓜电梯" 第一次作业是先来先服务的"傻瓜电梯",我当时觉得这个设计未免太简单了,于是就在傻瓜电梯 ...

  8. C#-WebForm-GridView表格展示数据

    GrideView 控件,功能是将数据库的数据用表格的形式展示在页面上 一.<源>代码中放入 GridView 控件 打开<设计>界面 二.绑定数据源 (一)创建 LinQ 类 ...

  9. 4. C++11非受限联合体

    在C/C++中,联合体是一种构造类型的数据结构.在一个联合体内,我们可以定义多种不同的数据类型,这些数据类型共享相同的内存空间,可以达到节省内存空间的目的. 1. 取消数据类型的限制 在C++98中, ...

  10. win10 安装 mysql 5.7

    win10 安装 mysql 5.7 1.在mysql 官网下载mysql 5.7 的手动安装包 mysql--winx64.zip 2. 解压到mysql 目录的文件夹下面 D:\moudle\my ...