核心目标:管理变化,提高复用
初学者有一个误区:把设计模式当成算法去学习,会去分析它的结构,理解代码的调用流程。这些在初学的时候是有必要的,但是这样是远远不够的。
学习设计模式时,核心目标要牢牢掌握:管理变化,提高复用!
你的设计方案是否达到了提高复用性的设计目标
- 误用了模式,你引入了一个设计模式,但是后来发现在这个场景下没有引入的必要性,并没有增加复用性。这样的话,就违背了引入设计模式的初衷:提高复用。
两种手段:分解vs.抽象
分解
- 在面向对象思想中,你首先是要思考如何分解
- 这和人认识世界的规律是一样的,小孩子刚开始认识这个世界的时候:这是梨,这是苹果,这是香蕉
- 建立一种分解的思维,知道它们有所不同
抽象
- 在分解之后,要建立一种抽象思维
- 一个小孩在过段时间他知道,这一类都归属于水果这个类型
- 在程序中,抽象出相同的行为与类,就可以建立统一的处理。水果具有哪些共同特征,交通工具都有哪些共同特征与行为。
所以,软件设计跟人认识世界的模型是非常类似的。
八大原则
这八大原则,比某一个具体的模式更重要。要将它们内化成一种认知,一种理解能力。
要对八大原则很熟,比如
- 策略模式,你一看这枚举类型,就发现它违背了开闭原则
- 桥模式,违背单一职责原则
- 除了单例、享元是处理性能问题的,其他设计模式都和八大原则有很大关系。
八大原则往往是相辅相成的,某一程度上是相通的
比如
- 你违背了依赖倒置原则,你往往就违背了开闭原则
- 你违背了单一职责原则,通常依赖倒置原则也违背了
重构技法
静态->动态
静态绑定的东西要转成动态绑定
早绑定->晚绑定
继承->组合
编译时依赖->运行时依赖
紧耦合->松耦合
从封装变化角度对模式分类
未被业界认可,是李建忠老师在教学、项目经验中总结出来的,觉得这种分类方式能够帮助大家更容易掌握设计模式。
有一些模式在当下比较不常用
- Builder
- Mediator
- Memento:被序列化的方案替代
- Iterator:C++泛型编程所发展出来的编译时多态,以模板的方式支持更灵活的迭代器
- Chain Of Resposibility:目前直接用某些数据结构就可以去表达了
- Command:在C++中,被仿函数替代
- Visitor:前提条件很苛刻,用的话也很重,会提出很庞大的类层次结构
- Interpreter:小而简单的文法可以用,更复杂的文法,用面向对象的方式也解决不了,管理也复杂,性能也下降,通常使用一些开源的工具来做
在C++对象模型的层面看设计模式
在C++中有三种结构
- A继承B的情况:在A的对象模型中,B的成员是在最前面的
- A组合一个B对象:这种情况和第一种情况的对象模型是一模一样的,B也是在A成员变量的前面
- A组合一个B指针:指针具有多态性,B指针可以指向它的子类,从而带来灵活性
如果把GoF所有设计模式的类名换成A、B等这种字母,你会发现几乎所有的模式都是图中的第三种结构
- 所有设计模式最后都是疏通同归,都是通过指针指向一个多态对象,从而实现灵活性
关注变化点和稳定点
- 如果你假设软件的所有地方都是变化的,那没有一个设计模式可以帮助到你
- 如果你假设软件的所有地方都是稳定的,那你完全没有必要用设计模式
因为设计模式的宗旨是:管理变化,提高复用。
因此,你应该区分清楚,哪些地方是稳定点,哪些地方是变化点,然后在变化点的地方应用合适的设计模式,从而达到管理变化,提高复用性的核心目的。
什么时候不用模式?
- 代码可读性很差时
- 变量命名、类层次结构很乱、文件划分、逻辑划分都很乱。那就没有必要用设计模式了,你先把代码的可读性理清楚。可以参考《重构》
- 需求理解还很浅时
- 对需求很懵懂的时候,先不用设计模式,把第一版本写出来。后面需求慢慢明确了,再用
- 变化没有显现时
- 变化没有显现时,你可能会预测变化,这时候会导致过度的使用设计模式
- 不是系统的关键依赖点
- 不是系统的关键模块,就没有必要用设计模式,比如一些外包型的公司,就不会去用。但是,如果是做产品级的软件,就会用设计模式,并且这会在将来的工作中受益
- 项目没有复用价值时
- 项目将要发布时
- 都要上线了,你不能引入设计模式,而引出了一些BUG
经验之谈
- 不要为模式而模式
- 关注抽象类和接口
- 理清变化点和稳定点
- 审视依赖关系
- 要有Framework和Application的区隔思维
- 良好的设计是演化的结果
设计模式成长的路径
“手中无剑,心中无剑”:见模式而不知
- 见到设计模式,你都不知道它是设计模式
“手中有剑,心中无剑”:可以识别模式,作为应用开发人员使用模式
- 会照猫画虎,能够从代码中识别出模式,并且知道怎么使用这些设计模式
“手中有剑,心中有剑”:作为框架开发人员为应用设计某些模式
- 你已经深入理解设计模式,你能知道怎么表达,你可以做一个框架开发人员,让别人来使用你的模式
“手中无剑,心中有剑”:忘掉模式,只有原则
- 已经忘记了有哪些设计模式,只记得了原则,根据这些原则,可以研究出自己的设计模式
- 代码只要符合某个设计原则,能够解决耦合性问题,得到复用性的提高。这就是一种设计模式