主旋律
处理类或对象的组合
Adapter 适配器
意图
将一个类的接口转换为客户希望的另外一个接口 可以使得接口不兼容不能一起工作的类可以一起工作
结构图 分两种
一种类适配器 一种对象适配器
协作
Client在Adapter实例上调用一些操作 接着适配器调用Adaptee的操作试下这个请求
适用性
- 你想使用一个已经存在的类 但是他的接口不符合我们的要求
- 创建一个可复用的类 该类可以与其他不相关的类或不可预见的类(即接口可能不一定兼容的类)协同工作
- 想使用已经存在的子类 但是又方便对每一个子类都适配去匹配他们的接口 这时
对象适配器
可以对父类适配
问题
- 重定义adaptee的行为比较困难
- 使用适配器的一个潜在问题是 他们不对所以的客户都透明
实现
- c++通常 public继承Target private继承adaptee
- 可插入的适配器
需要找到adaptee的窄接口 用于适配的最小的操作集 对于窄接口通常有以下三种方法
2.1 抽象(感觉类似于将窄接口的操作当做工厂方法)
2.2 使用代理对象(类似组合一个父类指针然后多态)
2.3 使用参数化的适配器
相关模式
- Bridge模式的出发点不同 Bridge模式的目的是将接口的部分和实现分离 从而可以更加独立的改变对象
而Adapter意味着改变一个已有对象的接口 - Decorator模式增加了其他对象的功能又不改变他们的接口 并且Decorator支持递归哈哈
- Proxy模式在不改变接口的情况下 定义了另一个对象的代理
Bridge 桥接
意图
将抽象部分与他的实现部分分离 使他们都可以独立变化
动机
- 继承机制使得客户端的代码与平台相关
适用性
- 不希望抽象和实现绑定
- 类的抽象和实现都可以各自通过子类扩充
- 等等等等 翻阅书籍P101
结构图
看起来就是将抽象的部分独立出去为一个抽象类 然后组合进实例的类中 以实现将实现和抽象分离的作用
实现
- 如何创建多个Implementor对象
- 构造传递一个Implementor实例
- 选择缺省实现
- 代理给一个对象
相关模式
- Abstract Factory 模式可以用来创建和配置一个特定的Bridge模式
- Adapter 模式用来协作无关紧要的类 通常在设计完成之后才会使用到 但是 Bridge 是系统设计开始就使用的
Composite 对象结构型模式
意图
将对象组合成树形结构以表示整体-部分
的层次结构
Composite使得用户对单个对象的组合对象的使用具有一致性
动机
一般会将一些图元对象进行组合表示为一个容器对象 但是使用这些类的代码就必须区分对待图元对象和容器对象
Composite模式描述了如何使用递归组合 使得用户不必对这些类进行区分
适用性
- 你想表示对象的
部分整体层次结构
- 希望用户可以忽略单个对象和组合对象的区别 用户将统一使用组队结构中的所有对象
结构图
实现
- 显示的父部件引用 保持从子部件到父部件的引用可以简化组合结构的遍历和管理 也可以简化结构的上移和组件的删除
同时父部件引用也支持Chain of Responsibility - 对于父部件引用必须维持一个不变式
即一个组合的所有子节点以这个组合为父节点
- 共享组件 一个组件只有一个父部件时很难共享组件
一个解决办法是为子部件存储多个父部件引用
- 最大化Component接口
- 声明管理子部件的操作 比如Add Remove等等
这需要在安全性和透明性做出抉择
5.1 声明在Component 有良好的透明性 但是对Leaf节点增加和删除对象是没有意义的
5.2 在Composite中声明 损失了透明性 Leaf 和 Composite 具有不同的接口
还有一个方法是在 Component 中声明一个 Componsite* GetComposite() Component 返回空 Componsite 返回 this
还一个方法是将 Component 中的 Add Remove 定义一个缺省的默认操作 但是这个操作其实有些问题 p111
- Component是否应该实现一个Component列表
- 子部件排序
- 使用高速缓冲存贮改善性能
- 由谁删除Component Composite被销毁时最好由Composite销毁其子节点
- 存贮组件用哪一种数据结构
相关模式
- 通常部件-父部件连接用于Chain of Responsibility
- Decorator通常与Composite一起使用 一起使用时他们通常有一个公共的父类 并且装饰需要支持Add Remove等
Decorator 装饰
意图
动态的给一个对象添加一些额外的职责 就增加功能来说 Decorator模式比子类更加灵活
动机
希望给某个对象添加功能而不是给这个类添加功能 可以将一个组件嵌入一个对象中 由这个对象添加组件 我们称这个嵌入的对象为装饰
装饰与他所装饰的组件需要接口一致 --- 所以可以递归的嵌套多个装饰 所以可以递归的嵌套多个装饰 所以可以递归的嵌套多个装饰
结构图
协作
- Decorator将请求转发给Component对象 并且可以在转发前后执行一些附加动作比如图中的AddedBehavior
相关模式
- Strategy 模式可以改变对象的内核 Decorator 模式可以改变对象的外表
Decorator 从外部改变组件 组价无需知道自己有哪些装饰 装饰对组件透明
Strategy 中 component 组件本身知道可能进行哪些扩充 必须引用并维护相应的策略
Facade 外观
意图
为子系统中的一组接口提供一个一致的界面 Facade模式定义了一个高层接口 这个接口使得这一子系统更容易使用
结构图
看起来就是充当外部与该子系统的接口 减少子系统与外部的依赖 子系统的使用也变得更简单 一般Facade看起来是一个Singleton即可
相关模式
- Abstract Factory模式可以与Facade一起使用以提供一个接口
这一接口可以用来以一种子系统独立的方式创建子系统对象
Abstract Factory也可以代替Facade隐藏那些与平台无关的类 - Mediator模式与Facade相似之处在于抽象了已有类的一些功能
但是Mediator目的在于对同事之间的任意通讯进行抽象 通常集中不属于任何单个对象的功能 - 一般Facade是一个Singleton
子系统并不需要知道Facade的存在
Flyweight 享元
意图
运用共享技术有效的支持大量细粒度对象
动机 这个模式看书比较快 这个模式看书比较快 这个模式看书比较快 有点复杂 在这里就不描述太多了
flyweight是一个共享对象可以同时存在于多个场景(context)中 并且在每个场景中的flyweight都可以作为一个独立的对象(这一点与非共享对象的实例没有区别)
flyweight不能对他所运行的场景做出任何假设
flyweight的关键概念在于内部状态和外部状态
内部状态
- 存储于flyweight中 包含了独立于独立于场景的信息
这些信息使得flyweight可以被共享
外部状态
- 取决于flyweight的场景 根据场景的变化而变化 所以不可以共享
重要重要重要 用户对象负责在必要的时候将外部状态传递给flyweight
具体例子看书P129
结构图
协作
- 注意参数的传递 外部状态由client对象存储或计算 用户调用Flyweight的操作时将该状态进行传递
用户不能直接创建ConcreteFlyweight对象 只能从FlyweightFactory对象获取ConcreteFlyw对象 这样才能保证共享
效果
- flyweight的传输查找计算外部状态等等都会产生开销 但是
空间上的节省
是其最大特点可以抵消这些时间开销 - Flyweight经常和Composite模式一起使用
实现
- 删除外部状态 这个模式的可用性很大程度上取决于是否很容易识别外部状态并将他从共享对象删除
如果不同种类的外部状态和共享对象目前的数目相同则删除外部状态不会降低存储消耗
理想状况是外部状态可以由一个单独的对象结构计算得到并且该结构的存储要求非常小
- 管理共享对象 比如上面的Factory
相关模式
- Flyweight经常和Composite模式一起使用 用
共享叶结点
的有向无环图
实现一个逻辑上的层次结构
Proxy 代理
意图
为其他对象提供一种代理以控制这个对象的访问
适用性
在需要比较通用和复杂的对象指针代替简单指针的时候使用Proxy模式
- 远程代理(Remote Proxy)
见名思意
- 虚代理(Virtual Proxy)
根据需要 根据需要 根据需要 根据需要 根据需要 根据需要 创建很大开销的对象
- 保护代理(Protection Proxy)
见名思意
- 智能指引或智能指针(Smart Reference 也叫 Smart Pointers)
见名思意
结构图
相关模式
- Adapter为他所适配的对象提供了不同的接口
相反
代理提供了与实体相同的接口可能代理的接口是实体接口的一个子集
- Decorator为对象添加一个或多个功能 而代理则是控制对象的访问
代理的实现与Decorator的实现类似 但是在相似的程度上有所差别
3.1 Protection Proxy 可能与 Decorator 的实现差不多
3.2 Remote Proxy 不包含对实体的直接引用而是一个间接引用 比如主机ID 主机上的局部地址
等
3.3 Virtual Proxy 开始的时候使用一个间接引用 比如文件名等 但是最终获取并使用一个直接引用因为这家伙按需创建