设计模式
设计模式概述
模式(Pattern)起源于建筑业而非软件业
定义
- 模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案。
软件模式概述
-
软件模式:在一定条件下的软件开发问题及其解法
- 问题描述
- 前提条件(环境或约束条件)
- 解法
- 效果
-
✓大三律(Rule of Three)
- 只有经过3个以上不同类型(或不同领域)的系统的校验,一个解决方案才能从候选模式升格为模式
设计模式(Design Pattern)
-
• 一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结
-
• 是一种用于对软件系统中不断重现的设计问题的解决方案进行文档化的技术
-
• 是一种共享专家设计经验的技术
-
• 目的:为了可重用代码、让代码更容易被他人理解、提高代码可靠性
-
设计模式的定义
- 设计模式是在特定环境下为解决某一通用软件设计问题提供的一套定制的解决方案,该方案描述了对象和类之间的相互作用。
-
4个关键要素
- • 模式名称 (Pattern Name)
- • 问题 (Problem)
- • 解决方案 (Solution)
- • 效果 (Consequences)
-
设计模式的分类
-
根据目的(模式是用来做什么的)可分
- 创建型模式主要用于创建对象
- • 结构型模式主要用于处理类或对象的组合
- • 行为型模式主要用于描述类或对象如何交互和怎样分配职责
-
根据范围
- 类模式处理类和子类之间的关系,这些关系通过继承建立,在编译时刻就被确定下来,是一种静态关系
- • 对象模式处理对象间的关系,这些关系在运行时变化,更具动态性
-
原则定义
-
单一职责原则:一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。
-
单一职责原则分析
- ✓一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小
- ✓当一个职责变化时,可能会影响其他职责的运作
- ✓将这些职责进行分离,将不同的职责封装在不同的类中
- ✓将不同的变化原因封装在不同的类中
- ✓单一职责原则是实现高内聚、低耦合的指导方针
-
-
开闭原则定义
-
✓开闭原则是面向对象的可复用设计的第一块基石,是最重要的面向对象设计原则
-
开闭原则:软件实体应当对扩展开放,对修改关闭。
- ✓抽象化是开闭原则的关键
- ✓相对稳定的抽象层 + 灵活的具体层
- ✓对可变性封装原则(Principle of Encapsulation of Variation, EVP):找到系统的可变因素并将其封装起来
-
-
里氏代换原则定义
-
所有引用基类的地方必须能透明地使用其子类的对象。
- ✓在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立。如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象
- ✓在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型
-
-
依赖倒转原则
-
依赖倒转原则:高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
-
依赖倒转原则定义
- ✓要针对接口编程,不要针对实现编程
- ✓在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中
-
-
接口隔离原则
-
接口隔离原则:客户端不应该依赖那些它不需要的接口。
- ✓当一个接口太大时,需要将它分割成一些更细小的接口
- ✓使用该接口的客户端仅需知道与之相关的方法即可
- ✓每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干
-
-
合成复用原则
-
合成复用原则又称为组合/聚合复用原则
- 合成复用原则:优先使用对象组合,而不是继承来达到复用的目的
-
-
迪米特法则
- 迪米特法则:每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
创建型模式
创建型模式(Creational Pattern)关注对象的创建过程
创建型模式对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离,对用户隐藏了类的实例的创建细节
创建型模式描述如何将对象的创建和使用分离
简单工厂模式
根据参数的不同返回不同类的实例
被创建的实例通常都具有共同的父类。
✓类创建型模式
✓要点:如果需要什么,只需要传入一个正确的参数,就可以获取所需要的对象,而无须知道其创建细节
简单工厂模式包含以下3个角色:
• Factory(工厂角色)
• Product(抽象产品角色)
• ConcreteProduct(具体产品角色)
工厂方法模式
工厂方法模式:定义一个用于创建对象的接口,但是让子
类决定将哪一个类实例化。工厂方法模式让一个类的实例化
延迟到其子类
工厂方法模式的定义
✓简称为工厂模式(Factory Pattern)
✓又可称作虚拟构造器模式(Virtual Constructor Pattern)
或多态工厂模式(Polymorphic Factory Pattern)
✓工厂父类负责定义创建产品对象的公共接口,而工厂子类则
负责生成具体的产品对象
✓目的是将产品类的实例化操作延迟到工厂子类中完成,即通
过工厂子类来确定究竟应该实例化哪一个具体产品类
工厂方法模式包含以下4个角色:
• Product(抽象产品)
• ConcreteProduct(具体产品)
• Factory(抽象工厂)
• ConcreteFactory(具体工厂)
✓在未使用配置文件和反射机制之前,更换具体工厂类需修改客户端源代码,但无须修改类库代码
模式优点
✓工厂方法用来创建客户所需要的产品,
同时还向客户隐藏了哪种具体产品类
将被实例化这一细节
✓能够让工厂自主确定创建何种产品对
象,而如何创建这个对象的细节则完
全封装在具体工厂内部
✓在系统中加入新产品时,完全符合开
闭原则
模式缺点
✓系统中类的个数将成对增加,在一定程
度上增加了系统的复杂度,会给系统带
来一些额外的开销
✓增加了系统的抽象性和理解难度
抽象工厂模式
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
抽象工厂模式的定义
✓又称为工具(Kit)模式
✓抽象工厂模式中的具体工厂不只是创建一种产品,它
负责创建一族产品
✓当一个工厂等级结构可以创建出分属于不同产品等级
结构的一个产品族中的所有对象时,抽象工厂模式比
工厂方法模式更为简单、更有效率
抽象工厂模式的结构
✓抽象工厂模式包含以下4个角色:
• AbstractFactory(抽象工厂)
• ConcreteFactory(具体工厂)
• AbstractProduct(抽象产品)
• ConcreteProduct(具体产品)
模式优点
✓隔离了具体类的生成,使得客户端并
不需要知道什么被创建
✓当一个产品族中的多个对象被设计成
一起工作时,它能够保证客户端始终
只使用同一个产品族中的对象
✓增加新的产品族很方便,无须修改已
有系统,符合开闭原则
模式缺点
✓增加新的产品等级结构麻烦,需要对原
有系统进行较大的修改,甚至需要修改
抽象层代码,这显然会带来较大的不便,
违背了开闭原则
模式适用环境
✓一个系统不应当依赖于产品类实例如何被创
建、组合和表达的细节
✓系统中有多于一个的产品族,但每次只使用
其中某一产品族
✓属于同一个产品族的产品将在一起使用,这
一约束必须在系统的设计中体现出来
✓产品等级结构稳定,设计完成之后,不会向
系统中增加新的产品等级结构或者删除已有
的产品等级结构
单例模式
单例模式:确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。
- ✓对象创建型模式
单例模式的定义
✓要点:
某个类只能有一个实例
必须自行创建这个实例
必须自行向整个系统提供这个实例
模式缺点
✓扩展困难(缺少抽象层)
✓单例类的职责过重
✓由于自动垃圾回收机制,可能会导致共
享的单例对象的状态丢失
模式优点
✓提供了对唯一实例的受控访问
✓可以节约系统资源,提高系统的性能
✓允许可变数目的实例(多例类)
模式适用环境
✓系统只需要一个实例对象,或者因为资
源消耗太大而只允许创建一个对象
✓客户调用类的单个实例只允许使用一个
公共访问点,除了该公共访问点,不能
通过其他途径访问该实例
适配器模式
适配器模式:将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。
适配器模式的结构
✓适配器模式包含以下3个角色:
• Target(目标抽象类)
• Adapter(适配器类)
• Adaptee(适配者类)
模式优点
✓ 将目标类和适配者类解耦,通过引入一个适配器
类来重用现有的适配者类,无须修改原有结构
✓ 增加了类的透明性和复用性,提高了适配者的复
用性,同一个适配者类可以在多个不同的系统中
复用
✓ 灵活性和扩展性非常好
✓ 类适配器模式:置换一些适配者的方法很方便
✓ 对象适配器模式:可以把多个不同的适配者适配
到同一个目标,还可以适配一个适配者的子类
模式缺点
✓类适配器模式:(1) 一次最多只能适配
一个适配者类,不能同时适配多个适配
者;(2) 适配者类不能为最终类;(3)
目标抽象类只能为接口,不能为类
✓对象适配器模式:在适配器中置换适配
者类的某些方法比较麻烦
模式适用环境
✓系统需要使用一些现有的类,而这些类
的接口不符合系统的需要,甚至没有这
些类的源代码
✓创建一个可以重复使用的类,用于和一
些彼此之间没有太大关联的类,包括一
些可能在将来引进的类一起工作
桥接模式
桥接模式:将抽象部分与它的实现部分解耦,使得两者都能够独立变化。
- ✓对象结构型模式
桥接模式的定义
✓又被称为柄体(Handle and Body)模
式或接口(Interface)模式
✓用抽象关联取代了传统的多层继承
✓将类之间的静态继承关系转换为动态的
对象组合关系
桥接模式的结构
✓桥接模式包含以下4个角色:
• Abstraction(抽象类)
• RefinedAbstraction(扩充抽象类)
• Implementor(实现类接口)
• ConcreteImplementor(具体实现类)
模式优点
✓分离抽象接口及其实现部分
✓可以取代多层继承方案,极大地减少
了子类的个数
✓提高了系统的可扩展性,在两个变化
维度中任意扩展一个维度,不需要修
改原有系统,符合开闭原则
模式缺点
✓会增加系统的理解与设计难度,由于关
联关系建立在抽象层,要求开发者一开
始就针对抽象层进行设计与编程
✓正确识别出系统中两个独立变化的维度
并不是一件容易的事情
模式适用环境
✓ 需要在抽象化和具体化之间增加更多的灵活性,
避免在两个层次之间建立静态的继承关系
✓ 抽象部分和实现部分可以以继承的方式独立扩展
而互不影响
✓ 一个类存在两个(或多个)独立变化的维度,且
这两个(或多个)维度都需要独立地进行扩展
✓ 不希望使用继承或因为多层继承导致系统类的个
数急剧增加的系统
组合模式
组合模式:组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。
- ✓对象结构型模式
组合模式的结构
✓组合模式包含以下3个角色:
• Component(抽象构件)
• Leaf(叶子构件)
• Composite(容器构件)
模式优点
✓ 可以清楚地定义分层次的复杂对象,表示对
象的全部或部分层次,让客户端忽略了层次
的差异,方便对整个层次结构进行控制
✓ 客户端可以一致地使用一个组合结构或其中
单个对象,不必关心处理的是单个对象还是
整个组合结构,简化了客户端代码
✓ 增加新的容器构件和叶子构件都很方便,符
合开闭原则
✓ 为树形结构的面向对象实现提供了一种灵活
的解决方案
模式缺点
✓在增加新构件时很难对容器中的构件类
型进行限制
模式适用环境
✓在具有整体和部分的层次结构中,希望
通过一种方式忽略整体与部分的差异,
客户端可以一致地对待它们
✓在一个使用面向对象语言开发的系统中
需要处理一个树形结构
✓在一个系统中能够分离出叶子对象和容
器对象,而且它们的类型不固定,需要
增加一些新的类型
装饰模式
装饰模式:动态地给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。
- ✓对象结构型模式
装饰模式的定义
✓以对客户透明的方式动态地给一个对象
附加上更多的责任
✓可以在不需要创建更多子类的情况下,
让对象的功能得以扩展
装饰模式的结构
✓装饰模式包含以下4个角色:
• Component(抽象构件)
• ConcreteComponent(具体构件)
• Decorator(抽象装饰类)
• ConcreteDecorator(具体装饰类)
模式优点
✓ 对于扩展一个对象的功能,装饰模式比继承
更加灵活,不会导致类的个数急剧增加
✓ 可以通过一种动态的方式来扩展一个对象的
功能,通过配置文件可以在运行时选择不同
的具体装饰类,从而实现不同的行为
✓ 可以对一个对象进行多次装饰
✓ 具体构件类与具体装饰类可以独立变化,用
户可以根据需要增加新的具体构件类和具体
装饰类,且原有类库代码无须改变,符合开
闭原则
模式缺点
✓使用装饰模式进行系统设计时将产生很
多小对象,大量小对象的产生势必会占
用更多的系统资源,在一定程度上影响
程序的性能
✓比继承更加易于出错,排错也更困难,
对于多次装饰的对象,调试时寻找错误
可能需要逐级排查,较为烦琐
模式适用环境
✓在不影响其他对象的情况下,以动态、
透明的方式给单个对象添加职责
✓当不能采用继承的方式对系统进行扩展
或者采用继承不利于系统扩展和维护时
可以使用装饰模式
外观模式
外观模式:为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- ✓对象结构型模式
- 外观模式的定义
✓又称为门面模式
✓是迪米特法则的一种具体实现
✓通过引入一个新的外观角色来降低原有
系统的复杂度,同时降低客户类与子系
统的耦合度
✓所指的子系统是一个广义的概念,它可
以是一个类、一个功能模块、系统的一
个组成部分或者一个完整的系统 - 外观模式的结构
✓外观模式包含以下2个角色:
• Facade(外观角色)
• SubSystem(子系统角色) - 模式优点
✓ 它对客户端屏蔽了子系统组件,减少了客户
端所需处理的对象数目,并使得子系统使用
起来更加容易
✓ 它实现了子系统与客户端之间的松耦合关系,
这使得子系统的变化不会影响到调用它的客
户端,只需要调整外观类即可
✓ 一个子系统的修改对其他子系统没有任何影
响,而且子系统的内部变化也不会影响到外
观对象 - 模式缺点
✓不能很好地限制客户端直接使用子系统
类,如果对客户端访问子系统类做太多
的限制则减少了可变性和灵活性
✓如果设计不当,增加新的子系统可能需
要修改外观类的源代码,违背了开闭原
则 - 模式适用环境
✓要为访问一系列复杂的子系统提供一个
简单入口
✓客户端程序与多个子系统之间存在很大
的依赖性
✓在层次化结构中,可以使用外观模式的
定义系统中每一层的入口,层与层之间
不直接产生联系,而是通过外观类建立
联系,降低层之间的耦合度
享元模式
享元模式:运用共享技术有效地支持大量细粒度对象的复用。
- ✓对象行为型模式
- 享元模式的结构
✓享元模式包含以下4个角色:
• Flyweight(抽象享元类)
• ConcreteFlyweight(具体享元类)
• UnsharedConcreteFlyweight(非共享具体享元类)
• FlyweightFactory(享元工厂类) - 模式优点
✓可以减少内存中对象的数量,使得相
同或者相似的对象在内存中只保存一
份,从而可以节约系统资源,提高系
统性能
✓外部状态相对独立,而且不会影响其
内部状态,从而使得享元对象可以在
不同的环境中被共享 - 模式缺点
✓使得系统变得复杂,需要分离出内部状
态和外部状态,这使得程序的逻辑复杂
化
✓为了使对象可以共享,享元模式需要将
享元对象的部分状态外部化,而读取外
部状态将使得运行时间变长 - 模式适用环境
✓一个系统有大量相同或者相似的对象,
造成内存的大量耗费
✓对象的大部分状态都可以外部化,可以
将这些外部状态传入对象中
✓在使用享元模式时需要维护一个存储享
元对象的享元池,而这需要耗费一定的
系统资源,因此,在需要多次重复使用
享元对象时才值得使用享元模式
代理模式
代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。
- ✓对象结构型模式
- 代理模式的定义
✓引入一个新的代理对象
✓代理对象在客户端对象和目标对象之间
起到中介的作用
✓去掉客户不能看到的内容和服务或者增
添客户需要的额外的新服务 - 代理模式的结构
✓代理模式包含以下3个角色:
• Subject(抽象主题角色)
• Proxy(代理主题角色)
• RealSubject(真实主题角色) - 模式优点
✓能够协调调用者和被调用者,在一定
程度上降低了系统的耦合度
✓客户端可以针对抽象主题角色进行编
程,增加和更换代理类无须修改源代
码,符合开闭原则,系统具有较好的
灵活性和可扩展性 - 模式优点——逐个分析
✓ 远程代理:可以将一些消耗资源较多的对象和操
作移至性能更好的计算机上,提高了系统的整体
运行效率
✓ 虚拟代理:通过一个消耗资源较少的对象来代表
一个消耗资源较多的对象,可以在一定程度上节
省系统的运行开销
✓ 缓冲代理:为某一个操作的结果提供临时的缓存
存储空间,以便在后续使用中能够共享这些结果,
优化系统性能,缩短执行时间
✓ 保护代理:可以控制对一个对象的访问权限,为
不同用户提供不同级别的使用权限 - 模式缺点
✓由于在客户端和真实主题之间增加了代
理对象,因此有些类型的代理模式可能
会造成请求的处理速度变慢(例如保护
代理)
✓实现代理模式需要额外的工作,而且有
些代理模式的实现过程较为复杂(例如
远程代理) - 模式适用环境
✓ 当客户端对象需要访问远程主机中的对象时可以使用远程
代理
✓ 当需要用一个消耗资源较少的对象来代表一个消耗资源较
多的对象,从而降低系统开销、缩短运行时间时可以使用
虚拟代理
✓ 当需要为某一个被频繁访问的操作结果提供一个临时存储
空间,以供多个客户端共享访问这些结果时可以使用缓冲
代理
✓ 当需要控制对一个对象的访问,为不同用户提供不同级别
的访问权限时可以使用保护代理
✓ 当需要为一个对象的访问(引用)提供一些额外的操作时
可以使用智能引用代理
职责链模式
职责链模式:避免将一个请求的发送者与接收者耦合在一
起,让多个对象都有机会处理请求。将接收请求的对象连接
成一条链,并且沿着这条链传递请求,直到有一个对象能够
处理它为止。
- ✓对象行为型模式
- 职责链模式的定义
✓又称为责任链模式(翻译不同,☺)
✓将请求的处理者组织成一条链,并让请求沿着链传递,
由链上的处理者对请求进行相应的处理
✓客户端无须关心请求的处理细节以及请求的传递,只
需将请求发送到链上,将请求的发送者和请求的处理
者解耦 - 职责链模式的结构
✓职责链模式包含以下两个角色:
• Handler(抽象处理者)
• ConcreteHandler(具体处理者) - 纯的职责链模式
✓一个具体处理者对象只能在两个行为中选择一个:要
么承担全部责任,要么将责任推给下家
✓不允许出现某一个具体处理者对象在承担了一部分或
全部责任后又将责任向下传递的情况
✓一个请求必须被某一个处理者对象所接收,不能出现
某个请求未被任何一个处理者对象处理的情况 - 模式优点
✓使得一个对象无须知道是其他哪一个
对象处理其请求,降低了系统的耦合
度
✓可简化对象之间的相互连接
✓给对象职责的分配带来更多的灵活性
✓增加一个新的具体请求处理者时无须
修改原有系统的代码,只需要在客户
端重新建链即可 - 模式缺点
✓不能保证请求一定会被处理
✓对于比较长的职责链,系统性能将受到
一定影响,在进行代码调试时不太方便
✓如果建链不当,可能会造成循环调用,
将导致系统陷入死循环 - 模式适用环境
✓有多个对象可以处理同一个请求,具体
哪个对象处理该请求待运行时刻再确定
✓在不明确指定接收者的情况下,向多个
对象中的一个提交一个请求
✓可动态指定一组对象处理请求
命令模式
命令模式:将一个请求封装为一个对象,从而让你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
- ✓对象行为型模式
- 命令模式的定义
✓别名为动作(Action)模式或事务
(Transaction)模式
✓“用不同的请求对客户进行参数化”
✓“对请求排队”
✓“记录请求日志”
✓“支持可撤销操作” - 命令模式的结构
✓命令模式包含以下4个角色:
• Command(抽象命令类)
• ConcreteCommand(具体命令类)
• Invoker(调用者)
• Receiver(接收者) - 命令模式的实现
✓命令模式的本质是对请求进行封装
✓一个请求对应于一个命令,将发出命令的责任和执行
命令的责任分开
✓命令模式允许请求的一方和接收的一方独立开来,使
得请求的一方不必知道接收请求的一方的接口,更不
必知道请求如何被接收、操作是否被执行、何时被执
行,以及是怎么被执行的 - 模式优点
✓降低了系统的耦合度
✓新的命令可以很容易地加入到系统中,
符合开闭原则
✓可以比较容易地设计一个命令队列或
宏命令(组合命令)
✓为请求的撤销(Undo)和恢复(Redo)
操作提供了一种设计和实现方案 - 模式缺点
✓使用命令模式可能会导致某些系统有过
多的具体命令类(针对每一个对请求接
收者的调用操作都需要设计一个具体命
令类) - 模式适用环境
✓系统需要将请求调用者和请求接收者解
耦,使得调用者和接收者不直接交互
✓系统需要在不同的时间指定请求、将请
求排队和执行请求
✓系统需要支持命令的撤销(Undo)操作和
恢复(Redo)操作
✓系统需要将一组操作组合在一起形成宏
命令
解释器模式
解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
- ✓类行为型模式
- 解释器模式的定义
✓在解释器模式的定义中所指的“语言”
是使用规定格式和语法的代码
✓是一种使用频率相对较低但学习难度相
对较大的设计模式,用于描述如何使用
面向对象语言构成一个简单的语言解释
器
✓能够加深对面向对象思想的理解,并且
理解编程语言中文法规则的解释过程 - 解释器模式的结构
✓解释器模式包含以下4个角色:
• AbstractExpression(抽象表达式)
• TerminalExpression(终结符表达式)
• NonterminalExpression(非终结符表达式)
• Context(环境类) - 模式优点
✓易于改变和扩展文法
✓可以方便地实现一个简单的语言
✓实现文法较为容易(有自动生成工具)
✓增加新的解释表达式较为方便 - 模式缺点
✓对于复杂文法难以维护
✓执行效率较低 - 模式适用环境
✓可以将一个需要解释执行的语言中的句
子表示为一棵抽象语法树
✓一些重复出现的问题可以用一种简单的
语言来进行表达
✓一个语言的文法较为简单
✓执行效率不是关键问题
迭代器模式
迭代器模式:提供一种方法顺序访问一个聚合对象中各个元素,且不用暴露该对象的内部表示。
- ✓对象行为型模式
- 迭代器模式的结构
✓迭代器模式包含以下4个角色:
• Iterator(抽象迭代器)
• ConcreteIterator(具体迭代器)
• Aggregate(抽象聚合类)
• ConcreteAggregate(具体聚合类) - 模式优点
✓支持以不同的方式遍历一个聚合对象,
在同一个聚合对象上可以定义多种遍
历方式
✓简化了聚合类
✓由于引入了抽象层,增加新的聚合类
和迭代器类都很方便,无须修改原有
代码,符合开闭原则 - 模式缺点
✓在增加新的聚合类时需要对应地增加新
的迭代器类,类的个数成对增加,这在
一定程度上增加了系统的复杂性
✓抽象迭代器的设计难度较大,需要充分
考虑到系统将来的扩展。在自定义迭代
器时,创建一个考虑全面的抽象迭代器
并不是一件很容易的事情 - 模式适用环境
✓访问一个聚合对象的内容而无须暴露它
的内部表示
✓需要为一个聚合对象提供多种遍历方式
✓为遍历不同的聚合结构提供一个统一的
接口,在该接口的实现类中为不同的聚
合结构提供不同的遍历方式,而客户端
可以一致性地操作该接口
中介者模式
中介者模式:定义一个对象来封装一系列对象的交互。中介者模式使各对象之间不需要显式地相互引用,从而使其耦合松散,而且让你可以独立地改变它们之间的交互。
- ✓对象行为型模式
- 中介者模式的定义
✓又称为调停者模式
✓在中介者模式中,通过引入中介者来简化对象之间的
复杂交互
✓中介者模式是迪米特法则的一个典型应用
✓对象之间多对多的复杂关系转化为相对简单的一对多
关系 - 中介者模式的结构
✓中介者模式包含以下4个角色:
• Mediator(抽象中介者)
• ConcreteMediator(具体中介者)
• Colleague(抽象同事类)
• ConcreteColleague(具体同事类) - 模式优点
✓ 简化了对象之间的交互,它用中介者和同事
的一对多交互代替了原来同事之间的多对多
交互,将原本难以理解的网状结构转换成相
对简单的星型结构
✓ 可将各同事对象解耦
✓ 可以减少子类生成,中介者模式将原本分布
于多个对象间的行为集中在一起,改变这些
行为只需生成新的中介者子类即可,这使得
各个同事类可被重用,无须直接对同事类进
行扩展 - 模式缺点
✓在具体中介者类中包含了大量的同事之
间的交互细节,可能会导致具体中介者
类非常复杂,使得系统难以维护 - 模式适用环境
✓系统中对象之间存在复杂的引用关系,
系统结构混乱且难以理解
✓一个对象由于引用了其他很多对象并且
直接和这些对象通信,导致难以复用该
对象
✓想通过一个中间类来封装多个类中的行
为,又不想生成太多的子类
备忘录模式
备忘录模式:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样就可以在以后将对象恢复到原先保存的状态。
- ✓对象行为型模式
- 备忘录模式的定义
✓别名为标记(Token)模式
✓提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤
✓当前在很多软件所提供的撤销(Undo)操作中就使用了备忘录模式 - 备忘录模式的结构
✓备忘录模式包含以下3个角色:
• Originator(原发器)
• Memento(备忘录)
• Caretaker(负责人) - 模式优点
✓提供了一种状态恢复的实现机制,使
得用户可以方便地回到一个特定的历
史步骤
✓实现了对信息的封装,一个备忘录对
象是一种原发器对象状态的表示,不
会被其他代码所改动 - 模式缺点
✓资源消耗过大,如果需要保存的原发器
类的成员变量太多,就不可避免地需要
占用大量的存储空间,每保存一次对象
的状态都需要消耗一定的系统资源 - 模式适用环境
✓保存一个对象在某一个时刻的全部状态
或部分状态,这样以后需要时能够恢复
到先前的状态,实现撤销操作
✓防止外界对象破坏一个对象历史状态的
封装性,避免将对象历史状态的实现细
节暴露给外界对象
观察者模式
观察者模式:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新。
- ✓对象行为型模式
- 观察者模式的定义
✓别名
• 发布-订阅(Publish/Subscribe)模式
• 模型-视图(Model/View)模式
• 源-监听器(Source/Listener)模式
• 从属者(Dependents)模式 - 观察者模式的结构
✓观察者模式包含以下4个角色:
• Subject(目标)
• ConcreteSubject(具体目标)
• Observer(观察者)
• ConcreteObserver(具体观察者) - 模式优点
✓可以实现表示层和数据逻辑层的分离
✓在观察目标和观察者之间建立一个抽象的
耦合
✓支持广播通信,简化了一对多系统设计的
难度
✓符合开闭原则,增加新的具体观察者无须
修改原有系统代码,在具体观察者与观察
目标之间不存在关联关系的情况下,增加
新的观察目标也很方便 - 模式缺点
✓将所有的观察者都通知到会花费很多时
间
✓如果存在循环依赖时可能导致系统崩溃
✓没有相应的机制让观察者知道所观察的
目标对象是怎么发生变化的,而只是知
道观察目标发生了变化 - 模式适用环境
✓一个抽象模型有两个方面,其中一个方面依
赖于另一个方面,将这两个方面封装在独立
的对象中使它们可以各自独立地改变和复用
✓一个对象的改变将导致一个或多个其他对象
发生改变,且并不知道具体有多少对象将发
生改变,也不知道这些对象是谁
✓需要在系统中创建一个触发链
状态模式
状态模式:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
- ✓对象行为型模式
- 状态模式的定义
✓又名状态对象(Objects for States)
✓用于解决系统中复杂对象的状态转换以及不同状态下
行为的封装问题
✓将一个对象的状态从该对象中分离出来,封装到专门
的状态类中,使得对象状态可以灵活变化
✓对于客户端而言,无须关心对象状态的转换以及对象
所处的当前状态,无论对于何种状态的对象,客户端
都可以一致处理 - 状态模式的结构
✓状态模式包含以下3个角色:
• Context(环境类)
• State(抽象状态类)
• ConcreteState(具体状态类) - 模式优点
✓ 封装了状态的转换规则,可以对状态转换代码进
行集中管理,而不是分散在一个个业务方法中
✓ 将所有与某个状态有关的行为放到一个类中,只
需要注入一个不同的状态对象即可使环境对象拥
有不同的行为
✓ 允许状态转换逻辑与状态对象合成一体,而不是
提供一个巨大的条件语句块,可以避免使用庞大
的条件语句来将业务方法和状态转换代码交织在
一起
✓ 可以让多个环境对象共享一个状态对象,从而减
少系统中对象的个数 - 模式缺点
✓会增加系统中类和对象的个数,导致系统运
行开销增大
✓结构与实现都较为复杂,如果使用不当将导
致程序结构和代码混乱,增加系统设计的难
度
✓对开闭原则的支持并不太好,增加新的状态
类需要修改负责状态转换的源代码,否则无
法转换到新增状态;而且修改某个状态类的
行为也需要修改对应类的源代码 - 模式适用环境
✓对象的行为依赖于它的状态(例如某些
属性值),状态的改变将导致行为的变
化
✓在代码中包含大量与对象状态有关的条
件语句,这些条件语句的出现会导致代
码的可维护性和灵活性变差,不能方便
地增加和删除状态,并且导致客户类与
类库之间的耦合增强
策略模式
策略模式:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法可以独立于使用它的客户变化。
- ✓对象行为型模式
- 策略模式的定义
✓又称为政策(Policy)模式
✓每一个封装算法的类称之为策略(Strategy)类
✓策略模式提供了一种可插入式(Pluggable)算法的实现
方案 - 策略模式的结构
✓策略模式包含以下3个角色:
• Context(环境类)
• Strategy(抽象策略类)
• ConcreteStrategy(具体策略类) - 模式优点
✓ 提供了对开闭原则的完美支持,用户可以在
不修改原有系统的基础上选择算法或行为,
也可以灵活地增加新的算法或行为
✓ 提供了管理相关的算法族的办法
✓ 提供了一种可以替换继承关系的办法
✓ 可以避免多重条件选择语句
✓ 提供了一种算法的复用机制,不同的环境类
可以方便地复用策略类 - 模式缺点
✓客户端必须知道所有的策略类,并自行
决定使用哪一个策略类
✓将造成系统产生很多具体策略类
✓无法同时在客户端使用多个策略类 - 模式适用环境
✓一个系统需要动态地在几种算法中选择
一种
✓避免使用难以维护的多重条件选择语句
✓不希望客户端知道复杂的、与算法相关
的数据结构,提高算法的保密性与安全
性
模板方法模式
模板方法模式:定义一个操作中算法的框架,而将一些步
骤延迟到子类中。模板方法模式使得子类不改变一个算法的
结构即可重定义该算法的某些特定步骤。
- ✓类行为型模式
- 模板方法模式的定义
✓是一种基于继承的代码复用技术
✓将一些复杂流程的实现步骤封装在一系列基本方法中
✓在抽象父类中提供一个称之为模板方法的方法来定义
这些基本方法的执行次序,而通过其子类来覆盖某些
步骤,从而使得相同的算法框架可以有不同的执行结
果 - 模板方法模式的结构
✓模板方法模式包含以下两个角色:
• AbstractClass(抽象类)
• ConcreteClass(具体子类) - 模式优点
✓ 在父类中形式化地定义一个算法,而由它的
子类来实现细节的处理,在子类实现详细的
处理算法时并不会改变算法中步骤的执行次
序
✓ 提取了类库中的公共行为,将公共行为放在
父类中,而通过其子类来实现不同的行为
✓ 可实现一种反向控制结构,通过子类覆盖父
类的钩子方法来决定某一特定步骤是否需要
执行
✓ 更换和增加新的子类很方便,符合单一职责
原则和开闭原则 - 模式缺点
✓需要为每一个基本方法的不同实现提供
一个子类,如果父类中可变的基本方法
太多,将会导致类的个数增加,系统会
更加庞大,设计也会更加抽象(可结合
桥接模式) - 模式适用环境
✓一次性实现一个算法的不变部分,并将
可变的行为留给子类来实现
✓各子类中公共的行为应被提取出来,并
集中到一个公共父类中,以避免代码重
复
✓需要通过子类来决定父类算法中某个步
骤是否执行,实现子类对父类的反向控
制
访问者模式
访问者模式:表示一个作用于某对象结构中的各个元素的操作。访问者模式让你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
- ✓对象行为型模式
- 访问者模式的定义
✓它为操作存储不同类型元素的对象结
构提供了一种解决方案
✓用户可以对不同类型的元素施加不同
的操作 - 访问者模式的结构
✓访问者模式包含以下5个角色:
• Visitor(抽象访问者)
• ConcreteVisitor(具体访问者)
• Element(抽象元素)
• ConcreteElement(具体元素)
• ObjectStructure(对象结构) - 模式优点
✓增加新的访问操作很方便
✓将有关元素对象的访问行为集中到一
个访问者对象中,而不是分散在一个
个的元素类中,类的职责更加清晰
✓让用户能够在不修改现有元素类层次
结构的情况下,定义作用于该层次结
构的操作 - 模式缺点
✓增加新的元素类很困难
✓破坏封装 - 模式适用环境
✓一个对象结构包含多个类型的对象,希望对
这些对象实施一些依赖其具体类型的操作
✓需要对一个对象结构中的对象进行很多不同
的且不相关的操作,并需要避免让这些操作
“污染”这些对象的类,也不希望在增加新
操作时修改这些类
✓对象结构中对象对应的类很少改变,但经常
需要在此对象结构上定义新的操作