序
这个系列是关于设计模式的学习笔记。参考书目为经典的GoF。我会努力坚持将23个设计模式的学习笔记一一记录于此。同时,会使用c++来实现这些经典模式。
这篇笔记是本系列的第一篇,让我们开始设计模式之旅。
模式
定义
每一个模式,都描述了一个不断发生的问题,以及该问题的核心解决方案。这样就可以不断使用此方案,而避免无谓的重复劳动。
四要素
模式名称,问题,解决方案,效果
名称
助记名,用一两个词来描述问题,方案和效果。名称是抽象的表述,有助于记录,思考和交流。问题
描述何时使用该模式。解释问题和问题的前因后果。有时会包含使用模式的必要条件。解决方案
描述设计的组成成分,和他们的之间的关系,职责,协作方式。通常是抽象的,为了应用于多种不同的场合效果
描述了模式应用后的效果,和需要权衡的问题。包括对系统的灵活性、扩充性和可移植性的影响。
语言选择的影响
对于语言的选择,决定了哪些机制可以方便你的实现,哪些不能。
设计模式关系概览
设计模式如何解决问题
寻找合适的对象
设计中的抽象对于产生灵活的设计是至关重要的。设计模式帮你确定并不明显的抽象和描述这些抽象的对象。
决定对象的粒度
对象在大小和数目上变化极大。它们能表示下自硬件或上自整个应用的任何事物。不同的设计模式很好的描述了如何决定对象的粒度
指定对象接口
对象操作所定义的所有操作型构的集合被称为该对象的接口。对象接口描述了该对象所能接受的全部请求的集合。两个有相同接口的 对象可以有完全不同的实现。这为动态绑定和多态——面向对象系统的核心概念提供了条件。
设计模式通过确定接口的主要组成成分及经接口发送的数据类型,来帮助你定义接口。 设计模式也许还会告诉你接口中不应包括哪些东西。
运用复用机制
理解对象、接口、类和继承之类的概念对大多数人来说并不难,问题的关键在于如何运 用它们写出灵活的、可复用的软件。设计模式将告诉你怎样去做。
继承与组合的比较
继承通常被称为白箱复用,组合通常被称为黑箱复用。继承编译时绑定,可直接使用,但是破坏了封装性,而且缺少灵活性。组合依赖于接口,更灵活,但是更难与理解,运行效率相对较低。不过,从长远看人的低效才是最主要的,所以优先使用对象组合,而不是类继承委托
委托(delegation)是一种组合方法,它使组合具有与继承同样的复用能力。在委托方式下,两个对象共同处理一个请求,接收请求的对象将处理委托给代理者(delegate)。委托的主要优点在于它便于运行时刻组合对象操作以及改变这些操作的组合方式。在state, strategy, visitor等模式中使用了委托。委托是对象组合的特例。它告诉你对象组合作为一个代码复用机制可以替代继承。继承和参数化类型的比较
参数化类型即泛型。它允许你在定义一个类型时并不指定该类型所用到的其他所有类型。
设计应支持变化
设计模式可以确保系统能以特定方式变化,从而帮助你避免重新设计系统。下面阐述了一些导致重新设计的一般原因,以及解决这些问题的设计模式:
间接创建对象
避免通过类名显式创建类的设计模式:Abstract Factory, Factory Method, Prototype运行时改变请求响应方式
对特殊操作的依赖导致请求代码被写死,为避免此种情况而生的设计模式:Chain of Responsibility, Command平台移植性
对特殊平台的依赖,导致代码不可移植,限制平台相关性的设计模式:Abstract Factory, Bridge阻止连锁变化
对对象的表示或实现的依赖会在对象改变时产生连锁依赖,接触这些依赖的设计模式:Abstract Factory, Bridge, Memento, Proxy孤立算法
算法在开发中会迭代和变化,孤立特定算法的设计模式:Builder, Iterator, strategy, Template Method, visitor松耦合
紧耦合很难被复用,松耦合更利于学习、移植、修改、扩展。松耦合设计模式:Abstract Factory, Command, Facade, Mediator, Observer, Chain of Responsibility组合使用继承和组合
过多的继承导致类爆炸,过度的使用组合导致难于理解。综合使用继承和组合的设计模式:Bridge, Chain of Responsibility, Composite, Decorator, Observer, strategy方便的修改类
有时因为没有源码或者需要改变很多子类导致难以修改一个类。对一个难以修改的类进行修改的设计模式:Adapter, Decorator, visitor
怎样选择设计模式
- 考虑设计模式是怎样解决设计问题的
- 浏览模式的意图部分
- 研究模式怎样互相关联
- 研究目的相似的模式
- 检查重新设计的原因
- 考虑你的设计中哪些是可变的
怎么使用设计模式
- 大致浏览一遍模式
- 回头研究结构部分、参与者部分和协作部分
- 看代码示例部分
- 选择模式参与者的名字,使它们在应用上下文中有意义
- 定义类
- 定义模式中专用于应用的操作名称
- 实现执行模式中责任和写作的操作