创建高质量的类
成为高效程序员的一个关键就在于,当你开发程序任何一部分代码时,都能安全地忽视程序中尽可能多的其余部分。
1、抽象
类 = ADT(抽象数据类型)+ 继承 + 多态
创建高质量类的最关键一步是创建一个好的接口(这里的接口指的是类中能够被外部访问的方法)。
类的接口应该提供一致的抽象。很多问题都是由于违背该原则而引起的。
一个呈现出很好的抽象的类接口通常也有很高的内聚性。而具有很强内聚性的类往往也会呈现为很好的抽象。
在设计类或类中的方法时,要尽量符合单一职责原则,使其具有高内聚性。
ADT:一些数据以及对这些数据所进行的操作的集合
2、封装
封装的原则:
- 尽可能的限制类和成员的可访问性(无法确定时,采用最严格的访问级别)
- 不要公开暴露成员数据(暴露成员数据会破坏封装性,从而限制你对这个抽象的控制能力)
- 不要对类的使用者做任何假设
- 让阅读代码比编写代码更方便(如果必须看到底层实现才能理解发生的事情,那还算不上抽象)
- 类与类之间应该是低耦合的
3、组合(has a)
- 组合是一个简单概念,表示一个类含有一个基本数据元素或对象
- 继承比组合更复杂,更容易出错。组合是面向对象的主力技术
- 要警惕包含有超过5个数据成员(引用对象)或9个数据成员(简单数据类型)的类,可以考虑将其拆分到更小的类中
4、继承(is a)
- 继承应该遵循 Liskov 替换原则
- 继承体系不要太深,尽量限制在3层之内
- 继承会破坏封装性。父类的所有数据应该都是private,子类通过其提供的get/set来访问数据
- 继承会增加管理复杂度
5、组合与继承的选择
从管理复杂度来说,应该少使用继承,多使用组合。
什么时候可以使用继承,何时又该使用组合:
- 如果多个类共享数据而非行为,应该创建这些类可以包含的共用对象
- 如果多个类共享行为而非数据,应该让他们从共同的父类继承而来,并在父类里定义共用的方法
- 如果多个类机共享数据也共享行为,应该让他们从一个共同的父类继承而来,并在父类里定义共用的数据和方法
- 当你想由父类控制接口时,使用继承;当你想自己控制接口时,使用组合
6、成员方法和成员数据
有效地实现成员方法和成员数据的建议:
- 让类中方法的数量尽可能少
- 减少类所调用的不同方法(来自其他引用类型)的数量
- 对其他方法的间接调用要尽可能减少(迪米特法则)
- 一般来说,应尽量减少类和类之间相互合作的范围。尽量减少:
- 所实例化的对象的种类
- 在被实例化对象上直接调用 不同方法的数量
- 调用由其他对象返回的对象的方法的数量
7、构造函数
- 如果可能,应该在所有的构造函数中初始化所有的数据成员
- 优先采用深拷贝
8、创建类的理由
- 为现实世界中的对象建模
- 为抽象的对象建模(比如为Circle、Square抽象出 Shape类)
- 降低复杂度
- 隔离复杂度
- 隐藏实现细节
- 限制变动所影响的范围
- 隐藏全局数据
- 让参数传递更加顺畅
- 建立中心控制点
- 让代码更易于重用
- 预计到某个程序会被修改
- 把相关的操作包装到一起(比如工具类)
- 实现特定的重构
9、应该避免的类
- 避免创建万能类
- 消除无关紧要的类(只包含数据而不包含行为的类)
- 避免用动词命名的类( 只有行为而没有数据的类往往不是一个真正的类)