设计模式之七大原则
设计模式(面向对象)有七大原则:
1.开放-封闭原则:总纲,对扩展开放,对修改关闭;
2.单一职责原则:实现类要职责单一;
3.依赖倒转原则:面向接口编程;
4.迪米特法则(也称为最小知识原则):降低耦合;
5.接口隔离原则:设计接口的时候要精简单一;
6.合成/聚合复用原则
7.里氏代换原则:不要破坏继承体系;
开放-封闭原则(Open Closed Principle):
定义:软件实体(类,模块,函数等等)应该可以扩展,但是不可以修改;
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。 这样的设计,能够面对需求改变却可以保持相对稳定,从而使系统在第一个版本以后不断推出新的版本;面对需求,对程序的改动是通过增加新的代码进行的,而不是更改现有的代码;
开放封闭原则,是最为重要的设计原则,Liskov替换原则和合成/聚合复用原则为开放封闭原则的实现提供保证。
迪米特法则(Law Of Demeter)
定义:如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用;
迪米特根本思想是:类之间的松耦合;
类之间的耦合越弱,越有利于复用,一个处于弱耦合的类被修改,不会对有关系的类造成波及。信息的隐藏促进了软件的复用;
广义的迪米特法则在类的设计上的体现:
优先考虑将一个类设置成不变类。
尽量降低一个类的访问权限。
谨慎使用Serializable。
尽量降低成员的访问权限。
依赖倒置原则(DependenceInversion Principle)
定义:A.高层模块不应该依赖低层模块。两个都应该依赖抽象;B.抽象不应该依赖细节,细节应该依赖抽象;(针对接口编程,而不是针对实现;)
面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变动时上层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。依赖倒转很好的解决了这个问题;
里氏替换原则(LiskovSubstitution Principle)
定义:子类型必须能够替换掉它们的父类型;
一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化;
只有子类可以替换父类,软件单位功能不受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为;里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
在进行设计的时候,我们尽量从抽象类继承,而不是从具体类继承。如果从继承等级树来看,所有叶子节点应当是具体类,而所有的树枝节点应当是抽象类或者接口。
单一职责原则(Single Responsibility Principle)
定义:就一个类而言,应该仅有一个引起它变化的原因; 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责变化可能会消弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏;
T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。也就是说职责P1和P2被耦合在了一起。
单一职责比较容易理解,但是在实际设计过程中容易发生职责扩散:因为某种原因,某一职责被分化为颗粒度更细的多个职责了。
解决办法:遵守单一职责原则,将不同的职责封装到不同的类或模块中。
合成/聚合原则(Composite/Aggregate Reuse Principle)
定义:尽量使用合成/聚合,尽量不要使用类继承; 优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物;
为什么尽量不要使用类继承而使用合成/聚合?
对象的继承关系在编译时就定义好了,所以无法在运行时改变从父类继承的子类的实现
子类的实现和它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化
当你复用子类的时候,如果继承下来的实现不适合解决新的问题,则父类必须重写或者被其它更适合的类所替换
接口隔离原则(ISP)
定义:一个类对另一个类的依赖应该建立在最小的接口上。
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
采用接口隔离原则对接口进行约束时,要注意以下几点:
接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
设计类型
设计模式分为那几类,它们是怎么区分的,每一种模式类型的特点,包含具体模式呢?
设计模式按照目的来分,可以分为创建型模式、结构型模式和行为型模式。
1.创建型
创建型模式用来处理对象的创建过程,主要包含以下5种设计模式:
工厂方法模式(Factory Method Pattern)
抽象工厂模式(Abstract Factory Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)
单例模式(Singleton Pattern)
2.结构型
结构型模式用来处理类或者对象的组合,主要包含以下7种设计模式:
适配器模式(Adapter Pattern)
桥接模式(Bridge Pattern)
组合模式(Composite Pattern)
装饰者模式(Decorator Pattern)
外观模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
3.行为型
行为型模式用来对类或对象怎样交互和怎样分配职责进行描述,主要包含以下11种设计模式:
责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
备忘录模式(Memento Pattern)
观察者模式(Observer Pattern)
状态模式(State Pattern)
策略模式(Strategy Pattern)
模板方法模式(Template Method Pattern)
访问者模式(Visitor Pattern)
总结
设计原则是实现代码复用,增加可维护性。而设计模式就是实现了这些原则,达到了代码复用和增加可维护行的目的。设计模式的重点还是熟练理解理论知识的基础上能够做大灵活的应用,让设计出来的系统更加健壮,代码更加优化。前期刚学习的时候,做到能够套用,随着熟练程度的加深,达到无招胜有招,将各种模式融合的系统的实践中。