01 概述
设计模式的基础是:多态。
学习设计模式将有助于更加深入地理解面向对象思想,让你知道:
1、如何将代码分散在几个不同的类中?
2、为什么要有“接口”?
3、何谓针对抽象编程?
4、何时不应该使用继承?
5、如何不修改源代码增加新功能?
6、更好地阅读和理解现有类库与其他系统中的源代码。
推荐书籍:
《设计模式:可复用面向对象软件的基础》
《大话设计模式》
02 分类
1、从目的来看:
创建型模式
结构型模式
行为型模式
2、从范围来看:
类模式处理类与子类的静态关系
对象模式处理对象间的动态关系
3、从封装角度来看:
组件协作:Template Method,Strategy,Observer/Event
单一职责:Decorator,Bridge
对象创建:Factory Method,Abstract Factory,Prototype,Builder
对象性能:Singleton,Flyweight
接口隔离:Façade,Proxy,Mediator,Adaptor
状态变化:Memento,State
数据结构:Composite,Iterator,Chain of Responsibility
行为变化:Command,Visitor
领域问题:Interpreter
GoF提出的设计模型有23个,包括:创建型模式,结构型模式,行为型模式。简单工厂模式不属于GoF23种设计模式,因此设计模式目前分类:GoF的23种+简单工厂模式=24种。
2.1 创建型
创建型(Creational)模式:如何创建对象。
2.2 结构型
结构型(Structual)模式:如何实现类或对象的组合。
2.3 行为型
行为型(Behaviioral)模式:类或对象怎样交互以及怎样分配职责。
03 面向对象
从设计模式角度理解面向对象:
1、向下:面向对象三大机制
封装:隐藏内部实现
继承:复用现有代码
多态:改写对象行为
2、向上:深刻把握面向对象机制所带来的的抽象意义,理解如何使用这些机制来表达现实世界,掌握什么是“好的面向对象设计”。
如何解决复杂性?
1、分解
人们面对复杂性有一个常见的做法:即分而治之,将大问题分解为多个小问题,将复杂问题分解为多个简单问题。
2、抽象
更高层次来讲,人们处理复杂性有一个通用的技术,即抽象。由于不能掌握全部的复杂对象,我们选择忽视它的非本质细节,而去处理泛化和理想化的对象模型。
04 设计原则
对于面向对象软件系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题。如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决的核心问题之一。
设计原则最终目的:高内聚,低耦合。
4.1 单一职责原则SRP
单一职责原则(Single Responsibility Priciple,SRP):类的职责单一,对外只提供一种功能,引起类变化的原因应该只有一个。
4.2 开放封闭原则OCP
开闭原则(Open-Closed Priciple,OCP):对扩展开放,对更改封闭,即类的改动是通过增加代码进行的,而不是修改源代码。
类模块应该是可扩展的,但是不可修改。
4.3 Liskov替换原则LSP
里氏代换原则(Liskov Substitution Priciple,LSP):子类必须能够替换它们的基本(is-a),即任何抽象类出现的地方都可以用他的实现类进行替换,实际上就是虚拟机制,语言级别实现面向对象功能。
4.4 优先使用对象组合,而不是类继承
类继承通常为“白箱复用”,对象组合通常为“黑箱复用”。
继承在某种程度上破坏了封装性,子类父类耦合度高。
而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低。
4.5 依赖倒置原则DIP
依赖倒转原则(Dependence Inversion Priciple,DIP):高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)。
抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。即,依赖于抽象(接口),不要依赖具体的实现(类),也就是针对接口编程。
注:之所以叫依赖倒置,是相对于原来的高层依赖底层,抽象依赖具体的“倒置”。
4.6 接口隔离原则ISP
接口隔离原则(Interface Segregation Priciple,ISP):不应该强迫客户程序依赖它们不用的方法,一个接口应该只提供一种对外功能,不应该把所有操作都封装到一个接口中去。即接口应该小而完备。
注:单一职责原则说的是类,接口隔离原则说的是方法(接口)。
4.7 合成复用原则CRP
合成复用原则(Composite Reuse Priciple,CRP):类继承通常为“白箱复用”,对象组合通常为“黑箱复用”。
如果使用继承,会导致父类的任何交换都可能影响到子类的行为。继承在某种程度上破坏了封装性,子类父类耦合度高。而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低。
注:优先使用对象组合,而不是类继承。
4.8 封装变化点
使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。
4.9 迪米特法则LoD
迪米特法则(Law of Demeter,LoD)/最少知识原则:一个对象应当对其他对象尽可能少的了解,从而降低各个对象之间的耦合,提高系统的可维护性。
不将变量类型声明为某个特定的具体类,而是声明为某个接口。客户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案。
注:针对接口编程,而不是针对实现编程。
05 注意事项
什么时候不用设计模式?
1、代码可读性很差时
2、需求理解还很浅时
3、变化没有显现时
4、不是系统的关键依赖点
5、项目没有复用价值时
6、项目将要发布时