浅谈GOF设计模式之7大原则
7大原则
1.开闭(开放-封闭)原则
一个软件实体 如 类 模块 函数 等 对拓展开放,对修改关闭
注意:通过接口或者抽象类约束拓展,对拓展进行边界限定,不允许出现接口或抽象类中不存在的public方法
参数类型,引用对象尽量使用接口或者抽象类,而不是实现类
抽象层尽量保持稳定,一旦确定不允许修改
2.单一职责原则
一个类负责一个职责,一个类而言,应该仅有一个引起他变化的原因
优点:降低复杂度,降低变更引起的风险,提高可读性,维护性
建议:接口一定要做要单一职责,类的设计尽量做到只有一个原因引起变化
3.依赖倒转原则(策略模式)
依赖倒转原则是程序要依赖于抽象接口,不要依赖于具体实现,即要对抽象编程,不要对实现编程
注意:高层模块不应该依赖于底层模块,两个都应该依赖于其抽象;
抽象不应该依赖于细节,细节应该依赖抽象(具体类实现抽象类、接口),
对接口编程,不要对实现编程
程序中所有的依赖关系都终止于抽象类或接口
底层模块尽量都要有抽象类或者接口,或者两者都有
变量声明类型尽量是抽象类或者接口
使用继承时,尽量使用里氏替换原则
4.迪米特法则(最小知识原则):低耦合 高内聚
一个对象(类)应该对其他对象保持最少的了解。被调用的类内部如何复杂与我没有关系,只调用提供的public方法,just so so
含义:只和朋友交流(朋友类的定义:出现在成员变量,方法的输入输出参数中的类称为成员朋友类|而在方法内部新出现的类不属于朋友类)
每个类尽量降低成员变量的访问权限 (private protected default public 等严格控制)
类之间的通信尽量使用接口或者变量
5.里氏替换原则:集成与派生的规则
子类型必须要替换掉他们的父类型
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
子类可以增加自己特有的方法
当子类重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更加宽松
当子类实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类的更严格
注意:尽量不要重写父类的已经实现了的方法,可可以用接口等其他方法绕过
6.接口隔离原则
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少
理解:就是给每个类建立专用的接口,不要建立一个庞大的接口供所有类去调用,以来几个专用接口要比依赖一个综合接口更灵活
接口是设计时对外约束的契约,通过分散定义多个接口,以预防外来变更的扩散,提高系统的灵活性和可维护性
注意:接口尽量小,但要有限度(要适度细化接口)
为依赖接口的类定制服务,只暴露给调用的类他需要的方法,他不需要的方法隐藏,只有专注的为一个模块提供定制服务,才能建立最小的依赖关系
提高内聚,减少对外交互,是接口用最少的方法完成最多的事(适度)
7.组合/聚合复用原则(松耦合)
尽量合成和聚合,而不是集成(继承)来达到复用的目的
原则就在于一个新的对象里面使用一些已有的对象,使之成为新对象的一部分,新的对象通过想这些对象的委派达到复用已有功能的目的
这里的区别就是 has-a与 is-a 的区别
继承的缺点在于 父类的方法全部暴露给子类,父类如果发生变化,子类也得变化;聚合的复用对另外的类依赖的就比较少
其他术语
合成/聚合复用
优点:新对象存取成分对象的卫衣方法是通过成分对象的接口;
这种复用是黑箱操作,因为新对象对成分对象的内部细节是看不到的
这种复用支持包装;这种复用所需的依赖比较少
每一个新的类可以将焦点集中在一个任务上
这种复用可以在运行时动态进行,新对象可以使用合成/聚合关系将新的责任委派到合适的对象
缺点:通过这种方式复用建造的系统会有比较多的对象需要管理
继承复用
优点:新的实现较为容易,因为基类的大部分功能可以通过继承关系自动进入派生类
修改或扩展继承而来的实现较为容易
缺点:继承复用破坏包装,因为继承将基类的实现细节暴露给派生类,这种复用也称为白箱复用
如果基类的实现发生改变,那么派生类的实现也不得不发生改变
从基类继承而来实现是静态的,不可能在运行时发生改变,不够灵活