六大设计原则
单一职责原则
对于一个类,应该只有一个引起它变化的原因。
需要足够简单的逻辑,才可以在代码级别上违反单一职责原则。
需要类中的方法数目足够少,才可以在方法级别上违反单一职责原则。
当一个类承担了过多的职责是,就等同于将这些职责都耦合在一起,一个职责的变化会削弱这个类完成其他职责的能力,当发生变化时,设计将会脆弱。
优点 :
- 降低类的复杂度,一个类只负责一项职责,逻辑简单
- 提高类的可读性
- 提高系统的可维护性
里氏代换原则
子类型必须能够替换掉它们的父类型
正方形和长方形不符合里氏代换原则
只有满足了里氏替换原则,父类才能得到真正的复用,并且子类可以在父类的基础上添加新的行为。 此原则是对实现抽象化具体步骤的规范
开放封闭原则 OCP
开放封闭原则是面向对象开发中所有设计原则的核心。
添加而不是修改:对已有程序的拓展有限采用添加新的类或者模块的方式来进行,而不是通过修改现有的类或者模块来进行。
定义: 程序的实体对象(模块,类,函数等)应该可以进行拓展,但不应该可以修改。
特征:对于拓展是开放的,对于修改是封闭的。
意义:只依赖于抽象,核心思想就是面向抽象编程,而不是面向具体编程。抽象相对来说是稳定的。让类去依赖固定的抽象,所以对于修改来说是封闭。而通过面向对象的继承以及多态机制,可以实现对抽象体的继承,通过重写其方法来改变固有行为,从而实现新的拓展方法,所以对于拓展来说是开放的。
绝对封闭的系统不存在,若不能做到完全封闭,应该选择是对哪些变化进行封闭,哪些进行隔离。
依赖倒转原则
依赖倒转原则是面向对象设计的主要机制。
定义:程序的高层模块不应该依赖于低层模块,但两者都应依赖于抽象。抽象不应该依赖于具体细节,而细节应该依赖于抽象。
面向对象应该针对于接口编程,而不是针对实现编程
本质就是通过抽象(接口或者抽象类)是各个类或模块的实现彼此独立。
创建抽象化!!
合成/聚合复用原则
合成和聚合都是关联关系的特殊种类
合成本质上是值的聚合。聚合是引用的聚合。
两种基本方法实现复用:
- 通过合成、聚合
- 通过继承
定义: 尽量不使用类继承,而尽量使用合成、聚合
只有当以下条件满足时,才使用继承关系:
- 子类是父类的一个特殊种类,而不是父类的一个角色时
- 永远不会出现需要将子类转换成另外一个类的子类的情况时。
- 子类具有拓展父类的责任,而不是重写父类的方法时
- 只有在分类学上有意义时,才是用继承
is-a has-a的区分
is-a 代表一个类是另外一个类的一种
has-a 代表一个类是另外一个类的一个角色
优点:
- 新的对象存取子对象的唯一方法是通过子对象的接口
- 这种复用是黑箱的复用,子对象的细节对于新对象来说不可见
- 能够更好支持封装的特性
- 实现上的相互依赖性小
- 每一个新的类都可以将焦点集中在一个任务上
- 可以再运行时动态的进行,新的对象可以动态的引用与子对象类型相同的对象
- 作为复用手段可以用于任何环境
聚合是整体与部分的关系,表示含有,整体由部分组合而成,部分也可以作为独立个体存在
合成是一种更强的关系,部分组成整体,且不可分割,不能脱离整体独立存在。
迪米特法则
最少知识原则:一个对象应当尽可能少地了解其他对象(不和陌生人说话)
一个软件的实体应当尽可能少地与其他实体发生相互作用。
迪米特法则的初衷是降低类之间的耦合。
迪米特法则不希望类之间建立直接的接触。如果真的需要建立这种联系,希望通过其友元类传达。应用该法则造成的后果是:系统中存在大量的中介类,这些类完全是为了传递类之间的调用关系,增加了系统复杂性。
定义: 如果两个类之间不必直接通信,则这两个类不应该发生直接的相互作用。如果其中的一个类需要调用另一个类的某个方法,可以通过第三方来转发这个调用。
耦合性:程序结构中各个模块之间相互关联的度量。取决于各个模块之间接口的复杂程度,调用模块的方式以及哪些信息会通过接口。
模块接口的复杂性包括3个因素:
- 传送信息的数量,即有关的公共数据与调用的参数的数量
- 联系的方式
- 传送信息的结构
一个类公开的public属性或方法越多,修改时所涉及的面也就越大,变更这个类所引起的风险扩散也就越大。