设计模式(3):结构性模式
Contents
结构型模式涉及到如何组合类和对象已获得更大的结构。结构型类模式采用继承机制来组合接口实现。一个简单的例子是采用多重继承的方法将两个以上的类组合成一个类,结果这个类包含了所有父类的性质。
适配器使得一个接口与其他接口兼容,从而给出了多个不同接口的统一抽象。
结构型模型不是对接口和实现的进行组合,而是描述了如何对一些对象进行组合,从而实现新功能的一些方法。因为可以在运行时刻改变对象组合关系,所以对象组合方式具有更大的灵活性,而这种机制用静态类组合是不可能实现的。
Adapter(适配器)——类对象结构型模式
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能在一起工作的那些类可以在一起工作。
适用:
- 想使用一个已经存在的类,而它的接口不符合你的需求
- 想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作
- 想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口
考虑因素:
- Adapter的匹配程度
- 可插入的Adapter
- 使用双向适配器提供透明操作
最小接口集合仅包含两个操作:一个操作定义如何在层次结构中表示一个节点,另一个操作返回该节点的子节点。
对于窄接口的实现途径:
- 使用抽象操作
- 使用代理对象
- 参数化适配器
Bridge(桥接)——对象结构型模式
将抽象部分和实现部分分离,使它们都可以独立地变化。
当一个抽象可能有多个实现时,通常用继承来协调它们。
继承机制使得客户代码与平台相关。
适用:
- 不希望在抽象和它的实现部分之间有一个固定的绑定关系
- 类的抽象以及它的实现部分都可以通过生成子类的方法加以扩充
- 对一个抽象的实现部分的修改应对客户不产生影响
- 对客户完全隐藏抽象的实现部分
- 在多个对象之间实现共享,但同时要求客户并不知道这一点
- 有许多类要生成
优点:
- 分离接口及其实现部分
- 提高可扩充性
- 实现细节对客户透明
Composite(组合)——对象结构型模式
将对象组合成树形结构以表示“部分——整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
Composite模式的关键是一个抽象类,它既可以代表图元,又可以代表图元的容器。
适用:
- 想表示对象的部分-整体的层次结构
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
Composite模式:
- 定义了包含基本对象和组合的类层次结构
- 简化客户代码
- 使得更容易增加新类型的组件
- 使你的设计变得更加一般化
注意的问题:
- 显示的父部件引用
- 共享组件
- 最大化Component接口
- 声明管理子部件的操作
- Component是否应该实现一个Component列表
- 子部件排序
- 使用高速缓冲存贮改善性能
- 应该由谁删除Component
- 存贮组件最好用哪一种数据结构
仅当一个组件中增加或删除一个组件时,才改变这个组件的父部件。
Decorator(装饰)——对象结构型模式
动态的给一个对象添加一些额外的职责。——包装器Wrapper
将组件嵌入到另一个对象中,我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对该组件的客户透明。
适用:
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
- 处理那些可以撤销的职责
- 当不能采用生成子类的方法进行扩充时
优点和缺点:
- 比静态继承更灵活
- 避免在层次结构高层的类有太多的特征
- Decorator与它的Component不一样
- 有许多小对象
注意:
- 接口的一致性:装饰对象的接口必须与它所装饰的Component的接口一致
- 省略抽象的Decorator类
- 保持Component类的简单性:为了保证接口的一致性,组件和装饰必须有一个公共的Component父类
- 改变对象外壳与改变对象内核
FACADE(外观)——对象结构型模式
为子系统中的一组接口提供一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
将一个系统划分为若干个子系统有利于降低系统的复杂性。一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小。达到该目标的途径之一就是引入一个外观对象,它为子系统中较一般的设施提供了一个单一而简单的界面。
适用情况:
- 当你要为一个复杂子系统提供一个简单接口时
- 客户程序与抽象类的实现部分之间存在着很大的依赖性
- 当你需要构建一个层次结构的子系统时
客户程序通过发送请求给Facade的方式与子系统通讯,Facade将这些消息转发给适当的子系统对象。
使用Facade的客户程序不需要直接访问子系统对象。
优点:
- 对客户屏蔽了子系统组件,因而减少了客户处理对象的数目并使得子系统使用起来更加方便
- 实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是送紧合的
- 如果应用需要,它并不限制它们使用子系统类
注意:
- 降低客户-子系统之间的耦合度
- 公共子系统类与私有子系统类
Flyweight(享元)——对象结构型模式
通用共享技术有效的支持大量细粒度的对象
flyweight不能对它所运行的场景做出任何假设,这里的关键概念是内部状态和外部状态之间的区别。
flyweight模式对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模。
当以下情况都成立时使用:
- 一个应用程序使用了大量的对象
- 完全由于使用大量对象,造成很大的存储开销
- 对象的大多数状态都可以变为外部状态
- 如果删除对象的外部状态,那么可以用的相对较小的共享对象取代很多组对象
- 应用程序不依赖对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值
存储节约由一下几个因素决定:
- 因为共享,实例总数减少的数目
- 对象内部状态的平均数目
- 外部状态使计算还是存储的
节约存储的方法:
- 用共享减少内部状态的消耗
- 用计算时间换取对外部状态的存储
注意:
- 删除外部状态
- 管理共享对象
共享还意味着某种形式的引用计数和垃圾回收,这样当一个Flyweight不再使用时,可以回收它的存储空间。
Proxy(代理)——对象结构型模式
对其他对象提供一种代理以控制这个对象的访问
使用Proxy模式的常见情况:
- 远程代理(Remote Proxy)为一个对象在不同的地址和空间提供局部代表——可以隐藏一个对象存在于不同地址空间的事实
- 虚代理(Virtual Proxy)根据需要创建开销很大的对象——可以进行最优化
- 保护代理(Protection Proxy)控制对原始对象的访问
- 只能引用(Smart Reference)取代了简单的指针。它在访问对象时执行一些附加操作
——运行在访问一个对象时有一些附加的内务处理
一般来说,所有操作在指向实体的转发请求之前,都要检验这个要求是否合法,原始对象是否存在等。
Author: moyu-x
Link: http://moyu-x.com/2017/01/02/201701/DesignPattern-3/
License: 知识共享署名-非商业性使用 4.0 国际许可协议