Item 13 Minimize the accessibility of classes and members

239 阅读2分钟

区分好的模块和不好的模块最重要的因素是看这个模块对于其他模块而言是否隐藏内部数据和其他细节。好的模块会把所有细节隐藏起来,把API和实现隔离开来,模块之间用API通信。这就是information hiding或者封装(encapsulation)。是软件设计基本原则之一。

information hiding最大的意义在于it decouples(解耦) the modules that comprise a system. 这样模块就能独立开发、测试。提高了可重用性

Java中很多facility协助了信息隐藏,比如访问控制access control,决定了类,接口,成员的accessibility。

The rule of thumb: **尽可能使每个类或者成员不被外界访问。**也就是给最小的访问级别。


顶层类和接口

Top level(non-nested)的classes and interfaces,只有两种可能的访问级别:

  • package-priavte(笔者注:也就是default) The member is accessible from any class in the package where it is declared
  • public

成员(fields, methods, nested classes, and nested interfaces)

  • private—The member is accessible only from the top-level class where it is declared.
  • package-private—The member is accessible from any class in the package where it is declared. Technically known as default access, this is the access level you get if no access modifier is specified.
  • protected—The member is accessible from subclasses of the class where it is declared (subject to a few restrictions [JLS, 6.6.2]) and from any class in the package where it is declared.
  • public—The member is accessible from anywhere.

  • 从package-private变成protected时,accessibility会大大增强。protected members应该尽量少用。

  • 子类中覆盖的方法的访问级别不能低于父类的那个。特别的,对于接口来说,接口中所有的方法都隐含着公有访问级别;所以如果一个类实现了接口,接口中所有方法在这个类中也必须被声明为公有的。

  • instance field永远不能是public的。 Classes with public mutable fields are not thread-safe. 这一点也就解释了之前我讨论的为什么android中的context不能写成 public static Context context;(当然对于android来说,private也不行,因为context不能是static)。这一点我还是不太明白,主要不明白instance field是啥,与之对应的static field是啥。

  • 同样的建议适用于静态域。

总之,防止任何散乱的类、接口、成员变成API的一部分。除了Public static final的特殊情形,public class都不应该含有public fields. 还要确保public static final域的对象都是不可变的,比如,不能定义一个public static final Things[] VALUES = {...};因为非0数组是可变的。