在Java开发中,最常见的就是类和接口了,这是Java的核心,在这一章中也给在使用中提供了某些指导原则,让设计更合理。
类和成员的可访问性最小化
站在使用者的角度来看,对于某个模块功能,使用时我不需要知道内部是如何实现的,只需要给我一个接口,我调用就能完事是最好的,将内部的实现隐藏。这就是信息隐藏或封装。
这个设计原则可以解除当前模块与其他模块的耦合关系,也能让内部的实现能更好的修改和重构,而且暴露的接口越多,那么需要维护的功能也会越多。
对于所有的字段、方法、内部类和内部接口都有四种访问级别:
- private
- package-private
- protected
- public
第二种没有关键字,不写限制就是包级私有,即缺省。
在公有类种使用访问方法而非公有域
如果直接访问公有域,会存在无法添加辅助功能,虽然写起来可能简便一点,但是在设计上,是不合理的。总之不要暴露可变的域。
使可变性最小化
让实例成为不可变的,最大的好处就是线程安全,对于这个实例可以任意使用。
而要让类成为不可变需要满足以下规则:
- 不要提供任何修改对象状态的方法
- 保证类不能被扩展,使用finial关键字
- 使所有域都是final的
- 使所有域都是private的
- 确保任何可变组件的互斥访问,即保证不能让类的方法直接获取到指向可变对象的域(即某个类的实例)
当然不可变类的缺点就是对于每个不同的值都需要一个单独的对象。有时候创建这种对象的代价还不低。
如果类不能做成不可变的,那么也应该尽可能的减小可变的因素。
复合优先于继承
要么为继承而设计并提供文档说明,要么就不要使用继承
不是说继承不好,而是在多人合作的时候,错误的使用了继承。如果在一个模块功能的开发时,只有一个人开发或者说有良好的文档,在可以使用继承的情况下使用能极大程度的简化某些功能开发。
而使用复合,相当于新建一个类,将另一个类的功能包装起来。
而类继承的文档需要包含可覆盖的方法调用了其他哪些可覆盖的方法,并说明在什么情况下去覆盖。
总而言之,在目前看来只有在你能掌控的范围和在有明确说明或了解的情况下使用继承,其他时候使用复合更合适,使用复合的时候相当于提供一个辅助类,帮助实现这些接口。
接口优于抽象类
使用接口来定义功能的优点如下:
- 现有类可很容易被更新,实现新的接口
- 接口是定义混合类型的理想选择
- 接口允许我们构造非层次的类型框架
接口只用于定义类型
不要将接口用来定义常量,要定义这些常量应该放在一个不可实例化的工具类中。
类层次优于标签类
标签类就是那种通过某个字段去判断,使用if-else或者switch-case去判断实现逻辑。
这是不良的代码。这时候可以使用继承,不同的子类表示不同的逻辑。
用函数对象表示策略
例如排序策略,使用了Comparable接口,里边就一个方法compareTo(T t1,T t2),其中T就是一个泛型,代表传入的一个对象,这个对象引用具体的操作比较就是比较开放的,可自行实现。
优先考虑静态成员类
有四种嵌套类:
- 静态成员类
- 非静态成员类
- 匿名类
- 局部类
除了第一种,其他三种都叫做内部类。第一种最简单,完全可以看作是普通的类对待。
非静态成员类:每个内部类都能独立继承自一个接口的实现,所以无论外围类是否已经继承或实现了某个接口,对于内部类都是没有影响的。所以通过内部类,就能继承多个非接口的类。也可以在一个类中让多个内部类对一个接口进行不同的实现。
匿名类在回调中常常用到,但是注意异步回调时的内存泄漏问题,应保证回调与持有的类实例生命周期相同。
局部类:例如在方法中定义一个类,去使用,这种类使用场景较少。