模块设计是否良好,有个重要的因素在于,相对外部模块是否隐藏内部数据以及实现细节。
设计良好的模块会隐藏实现细节,并将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. ANE-如何加入ane,调试时又不报错

    有时候我们加入ane,即使没有调用ane的功能,debug的时候也会报错无法调试,这是为什么呢?因为我们的ane没有把default包含进去. 首先我们的extension.xml要把default节 ...

  2. Android App的破解技术有哪些?如何防止反编译?

     现在最流行的App破解技术大多是基于一定相关技术的基础:如一定阅读Java代码的能力.有一些Android基础.会使用eclipse的一些Android调试的相关工具以及了解一些smali的语法规范 ...

  3. DS作业01--日期抽象数据类型设计与实现

    第六次作业 1.思维导图及学习体会 1.1 思维导图 1.2 学习体会 因为假期里面代码的练习量很小,所以开学来上学期的知识遗忘了很多,刚刚开始写大作业的时候很困难,完全没有思路,后来看了几位同学的代 ...

  4. php防止网站被刷新

    在实际应用中,总会遇到某些页面被恶意用户刷新.当你的系统在某些模块没有使用缓存的时候,频繁的刷新会导致数据库吃紧.下面附上一段代码,防止频繁的刷新造成的死机情况. 主要是从 session方面进行限制 ...

  5. [原]时间格式化hh:mm:ss和HH:mm:ss区别

    hh:mm:ss   按照12小时制的格式进行字符串格式化 如果时间处于00:00:00——12:59:59,则返回的字符串正常 如果时间处于13:00:00——23:59:59,则返回的字符串是实际 ...

  6. 【JS新手教程】浏览器弹出div层1

    JS中,可以弹出一个层来进行提示等作用,方法是利用css样式display样式,当display等于none时,该元素就不会在页面显示出来,而且元素也不会占空间.就是用户触发某些事件时,动态修改该样式 ...

  7. PXE+Kickstart 批量安装CentOS 7

    安装之前 将需要安装 CentOS 的服务器与 PXE 服务器通过网络设备连接:PXE 服务器安装 CentOS,并且关闭firewalld.selinux,设置静态IP地址,本例设为10.0.0.1 ...

  8. orcal创建序列

    CREATE SEQUENCE flowjobseq --序列名INCREMENT BY 1 -- 每次加几个 START WITH 2000 -- 从1开始计数 NOMAXVALUE -- 不设置最 ...

  9. 【old】Python学习笔记

    上学期看视频记得,也没学到多少,目前打算一边通过<Python学习手册 第四版>提高核心语法(太厚了 噗),一边学习Python Web开发 然后这里的多任务编程和网络编程是暑假学的 5. ...

  10. dede发布内容限制违规词

    DEDE限制违规词代码 //词汇过滤检查 if( $cfg_notallowstr != '' ) { if(preg_match("#".$cfg_notallowstr.&qu ...