类/对象之间的关系:Generalization(泛化),Dependency(依赖),Association(关联),Aggregation(聚合),Composition(组合/合成)
泛化,表示类之间是is-a关系,如类A继承了B类或实现了B接口,子类会继承父类的属性和方法。
依赖,表示类之间是use-a关系,如该类A的方法中的参数是某个类B,类A和类B就是依赖关系(类B以局部变量、静态方法或方法参数的方式出现在类A中)。
关联:表示类A知道另一个类B的属性和方法的关系。可细分为组合关系和聚合关系。
聚合 :表示类之间has-a关系,如类A的成员变量有类B,但构造器中不用实例化类B。是整体和部分的弱的拥有关系,类B对象可以不在类A对象创建时创建。组合 :表示类之间has-a关系,如类A的成员变量有类B,且构造器中必须实例化类B或持有类B的实例。 是整体和部分的强的拥有关系,类A实例必须负责类B实例的生命周期,类B对象必须在类A对象创建时创建。
(1)针对接口编程
针对抽象编程,不要针对实现编程。
(2)单一职责原则
降低耦合,增强内聚。一个类最好工作单一,只关心自己范围内的工作。
(3)开闭原则
对扩展开放,对修改关闭。
(4)里氏代换原则
所有引用基类的地方必须能透明地使用其子类的对象。若对每一个T1类的对象o1,都有T2类的对象o2,使得T1定义的程序P在所有对象o1都替换成o2时,程序P的行为没有变化,那么T2类就是T1类的子类型。也就是说子类最好是用来扩展或实现父类的行为,而不是去改变某些行为。
(5)迪米特法则
若两个类不比彼此通讯,那么这两个类就不应该发生直接的相互作用。如果一个类需要调用另一个类的方法可以通过第三方转发这个调用。尽量降低类和成员的访问权限。只和朋友交流、慎用Serializable。
(6)合成/聚合复用原则
尽量使用合成/聚合,尽量不适用继承。
is-a符合继承关系,has-a符合聚合关系。
若两个类是has-a关系,但设计成了继承,肯定违反里氏代换原则。
Note:
- 继承会“白箱复用”,会将父类细节暴露给子类
- 如果父类更改,其所有子类也不得不改变
- 继承在运行时的行为不易改变
- 接口的大量不合理使用无法达到代码复用
- 找到应用中可能需要变化的地方并把它们独立出来,不要和固定代码混在一起
- 多用组合,少用继承