设计模式分析-转载
程序员文章站
2022-05-29 08:32:41
...
什么是设计模式:
解决某个问题的方案
每个模式有四个特征:
模式名
问题
解决方案
效果
MVC的设计模式:
界面设计中经常会使用类的模型/视图/控制器 (Model/View/Controller) 这三个东西.
Model可以看成是一个对象, View是它的显示, Controller是它的输入的响应
设计的原则:
把易变的部分与不变的部分分开, 使程序易于扩展
让对象间的耦合度降低,使一个对象的修改不会影响另外一个对象
复用的要点:
1 对接口而不是对实现编程
优点是:
客户不须知道他们使用的对象的特定类型,只知道对象有期望的接口
客户不须知道他们使用的对象是用什么类来实现的, 只知道定义接口的抽象类
结果可以避免各系统的依赖关系
2 优先使用对象组合成不是类继承
继承是通过对父类进行具体化来实现功能,继承在编译时确定,并且继承知道父类的实现,使子类与父类的依赖关系很紧密, 所以后面如果想维护时不好修改
组合是组装或是组合对象来实现更复杂的功能, 组合时只需要知道对象的接口实现的功能,而不需要知道对象的具体实现,所以依赖更少
委托是有两个对象参与处理一个请求,接收请求的对象把操作委托给它的代理者. 它是组合的一种对例
3 参数化类型
参数化类型是定义一个类型时不指定该类型所使用到的其它所有类型,未指定的类型在使用时以参数提供,这就是c++中的模板
这个一般用于解决操作时步骤基本相同,只是类型不同的场合,想更多的理解可以看STL库
4 聚合与相识
聚合表示一个对象拥有另一个对象或是对另一个对象负责
相识则是一个对象仅知道另一个对象, 有时也叫"关联" 或 "引用"
相识比聚合的耦合性要弱
模式的分类;
可以分成三类:
创建型模式: 用于对象过程的模式
结构型模式: 用于把不同的类或对象组合起来实现更复杂的功能
行为型模式: 用于规定不同类或对象间的交互方法或是职责,与结构型模式不同的是行为型模式中的对象是平行的,它们是交互的关系,而在结构型中它们是组合的关系,并且可能是包含的关系
/*-----------------------------------------------------------------------------
*
* 创建型模式 (用户类或对象的创建过程的模式)
*
*-----------------------------------------------------------------------------*/
对象创建型模式: 这个模式用于创建新的对象
特点:
隐藏具体实现: 把具体类的信息封装起来
隐藏创建过程: 隐藏了这些类的实例是如何被创建与放在一起的, 系统只知道这些对象中由抽象类所定义的接口
1 抽象工厂(Abstract Factory) - 对象创建型模式
抽象工厂:
创建一批抽象类的对象的工厂
目的:
提供一个创建一系列相关或相互依赖对象的接口,
而无需指定它们具体的类
实现:
参与者: 工厂Factory, 产品Product
Product是一批抽象类, 定义了产品的接口
Factory提*生Product的方法
具体的Factory提*生实例化的Product的方法
例子:
如gvim在Windows或是Linux上,窗口外观不一样,
但是窗口的组成部分基本一样(如都有标题栏,菜单,编辑区等),
相同控件的功能基本一样(如菜单的功能), 并且控件间可能有关联
这可以定义标题栏,菜单, 编辑区的抽象类定义它们的功能, 然后定义一套接口产生这些抽象类
2 生成器(Builder) - 对象创建型模式
生成器:
使用导向器引导类的创建过程,为相同的类创建不同对象的方法
目的:
将一个复杂对象的构建与它的表示分离,
使得同样的构建过程可以创建不同的表示
实现:
参与者:导向者director与生成器builder.
builder在构造函数中只进行基本的功能,
同时提供了其它接口进行对象的初始化,
director引导builder的构造过程,
调用builder的构造函数与其它初始化函数来创建builder,
并返回builder对象
class Builder{
public:
Builder(); // 构造函数
void BuildPartA(); // 初始化函数,初始化到状态A
void BuildPartB(); // 初始化函数,初始化到状态B
...
};
class Director{
public:
...
Builder* CreateBuilder1(){ // 引导生成的对像的构建过程
Builder* p = new Builder;
p->BuildPartA();
return p;
}
Builder* CreateBuilder2(){ // 引导生成的对像的构建过程
Builder* p = new Builder;
p->BuildPartB();
return p;
}
Builder* CreateBuilder3();
};
从上面的例子可以看出, builder只是提供基本的构造函数. 而具体生成怎样的builder由director决定. director封装了builder构造过程
builder模式把构造代码与表示代码分开, 因为builder的构造函数中并没有进行完整的构造, builder的构造是在director的CreateBuilderX中进行的. 你可以对它进行更多的订制.
我想这个应该适合一个对象可以有多个状态表示的时候. 如房间类, 假设内部的物品是一样的, 但不同的摆设会形成不同的房间. 而builder模式中使用director就可以为房间类导向而为每个房间生成不同的对象.
3 工厂方法(Factory Method) - 对象创建型模式
工厂方法:
creator的子类提供方法生产product对象
目的:
定义一个用于创建对象的接口,让子类决定实例化哪个类.Factory method使一个类的实例化延迟到子类
实现:
需要两个参与者:创建者creator与产品product,
1 product 对象定义基本的接口,
2 creator 定义创建 product 的接口.
3 creator 的子类实例化创建 product 的接口.
应用:
一般,如果creator与product有联系的话, 会使用这种方法.如在界面开发中的程序文档关系(Application,document,这个在Windos开发中经常会看到).
4 原型(ProtoType) - 对象创建型模式
原型:
通过调用原型的Clone方法创建新的对象,
新的对象不需要再进行其它特别的初始化(就达到与原型相同的状态)
目的:
用原型实例指定创建对象的种类, 并且通过拷贝这些原型创建新的对象
实现:
原型类提供一个Clone操作可以用来Clone自身状态
原型对象可能经过特别的初始化后才达到当前状态, 但下一个对象直接调用原型对象的Clone就可以直接达到这个状态而不需要再进行特别的初始化
应用:
这个方法一般用在系统中有几类不同的对象组成,这些对象区别的只是它们的状态, 如音符
5 单件(Singleton) - 对象创建型模式
单件:
类的实例只有并且只会有一个
目的:
保证类只有一个实例, 并提供一个访问它的全局访问点
实现:
c++中声明类的构造函数为非public的, 并且提供一个friend方式或是类的static方法来创建实例.
应用:
如果系统中一个类有多个实例会有问题, 就使用这个方法吧, 这样可以避免后面维护的人产生错误
/*-----------------------------------------------------------------------------
*
* 结构型模式
*
*-----------------------------------------------------------------------------*/
结构型模式: 通过组合类或对象来获得更大的结构并且得到新的功能
结合类的叫类对象结构型模式
结合对象的叫对象结构型模式
1 适配器(Adapter) - 类对象结构型模式
适配器:
用一个包装器Wrapper封装另外一个类并提供用户所希望的接口
目的:
将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原来由于接口不兼容而不能一起工作的那些类可以工作
实现:
定义一个新类Wrapper封装旧类,
新类通过调用旧类接口来提供用户希望的接口
2 桥接(Bridge) - 对象结构型模式
桥接:
类的抽象部分与实现部分都可以独立的变化
目的:
将抽象部分与它的实现部分分离, 使它们都可以独立的变化
原因;
当一个抽象可能会继承,
并且它的实现也有多种方式时,
它的抽象与实现都需要独立变化,
这时为了简化继承(而不是每个实现都有一个继承),
可以使用桥接的技术让实现也抽象化可以独立的变化,
而抽象部分也可以独立的变化
实现:
参与者:抽象Abstraction与实现Implementor
Abstraction定义抽象类的接口,并且维护一个指南Implementro类型对象的指针
Implementor定义实现类的接口, 该接口不一定要写Abstraction的接口一致. 一般来讲, Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作
作用: 如果你希望两个部分都可以独立变化的话, 那就用Bridge吧(一般是抽象有继承的条件下, 并且抽象的实现也需要变化的时候)
如果实现是固定的, 那直接使用继承就可以了不用Bridge
3 组合(Composite) - 对象结构型模式
组合:
操作时不管是对象还是对象的组合都一致同仁,如果是对象的组合的话对象的组合会把操作传到每个对象并返回一个最后的结果的
目的:
把对象组合成树形结构以表示"部分-整体" 的层次结构, 使用户对单个对象和组合对象的使用具有一致性
实现:
定义一个Component抽象类,为组合中的对象声明接口,声明一个接口用于访问和管理Component的子组件
Leaf表示叶节点对象,在组合中定义对象的行为
Composite定义有子部件的那些部件的行为,
并且存储子部件,同时实现与子部件相关的操作
Client通过Component接口操纵组合部件的对象
一个组件可以添加到另外一个组件中从而组成一棵树, 接收到请求时会把请求一层一层往下传直到叶子
解决的问题:
表示部分-整体观点,简化其它部分的操作代码
适用性;
想表示对象的部分-整体层次结构
想用户忽略组合对象与单个对象的不同,用户将统一的使用组合结构中的所有对象
应用;
作者的例子是计算机报价单, 确实使用报价单的话最后对一个组合求价格更方便一些
装饰(Decorator) - 对象结构型模式
装饰:
对象A给对象B添加功能,并且对象A提供的接口与对象B一样
目的:
动态的给一个对象添加一些额外的职责,就增加功能来说,装饰比生成子类更灵活
实现: 参与者:组件Component与装饰者Decorator
Decorator维持一个指向Component对象的指针, 并定义一个与Component接口一致的接口(一般继承相同的抽象类),它将给Component动态的添加职责
应用:
想给一个类扩展一些功能,但是又不想产生子类的时候
在不影响其它对象的情况下以动态透明的方式给单个对象添加职责
处理那些可以撤消的职责
4 外观(Facade) - 对象结构型模式
外观:
为一组接口提供一个一致的界面
目的:
为子系统中一组接口提供一个一致的界面.
Facade定义了一个高层接口, 这个接口使得这一子系统更加容易使用
原因:
把一个系统分成若干个子系统有利于降低系统的复杂性,
为了让子系统间的通信与相互依赖关系达到最小,
使用外观的方法可以为子系统提供一个单一而简单的界面
结果:
让这个子系统与外界的耦合性最小, 并且这组子系统更容易使用
其实就像是库的接口那样,它们提供了一个简单的功能给外面
5 享元(Flyweight) - 对象结构型模式
享元:
不同场景中出现同一个对象,那可以把它们只看成一个对象的共享,场景中只存储它们的外部状态与对这个对象的引用
目的:
运用共享技术有效的支持大量细粒度的对象
实现:
实现一般包括flyweight与flyweightfactory,client三个部分
flyweight是一个共享对象, 它会同时出现在多个场景(context), 并且每个场景中都可以做为一个独立的对象. 但是, 它不能对它所运行的场景做出任何假设。
为了实现flyweight对象, 可以把flyweight的状态分成内部状态与外部状态, 独立于场景的就叫内部状态,flyweight只保存内部状态. 与场景相关的就叫外部状态, 用户在调用时把外部状态传给Flyweight
flyweightfactory创建并管理flyweight对象
client维持对flyweight的引用,并且存储一个或多个flyweight的外部状态
例子:
如一个字处理器,它的享元是每个字符, 内部状态是字符值,外部状态是这个字的位置,大小等
作用: 理论就是如果一个对象需要在多个地方出现,并且只有状态不同时,可以使用享元的办法把内部状态保存在享元中,外部状态在调用这个对象时传入
可以减少系统中对象的数目
6 代理(Proxy) - 对象结构型模式
代理: 控制对另外一个对象的访问
目的; 为其它对象提供一个代理以控制对这个对象的访问
实现: 跟经济人的意思差不多, 也就是因为某种原因而不想让其它人直接访问主角而采取的一种措施
/*-----------------------------------------------------------------------------
*
* 行为模式
*
*-----------------------------------------------------------------------------*/
行为模式: 描述对象或类间行为的模式
行为类模式: 使用继承机制在类间分派行为
行为对象模式: 使用对象复合而不是继承来实现:
1 一组对等的对象怎样想到协作以完成其中任一个对象都无法完成的任务
2 把行为封状在一个对象中并将请求指派给它
1 职责链(Chain of responsibility) - 对象行为型模式
职责链:
多个对象连成一条链, 每个请求都在这条链中从头到尾传送直到有对象处理它为止
目的:
把发送者与接收者的耦合去掉
使多个对象都有机会处理请求。装这些对象连成一条链,并沿着这条链发送请求,直到有一个对象处理它为止。
应用:
多个对象可以处理一个请求,哪个对象处理该请求运行时自动确定
想在不明确指定接收者的情况下,向多个对象中的一个提交请求
可处理一个请求的对象集合应该被动态指定
2 命令(Command) - 对象行为型模式
命令: 每个请求都是一个对象,对于过程语言则是每个请求都有一个回调关联
目的: 将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,及支持可撤消的操作
功能: 你可以进行命令排队, 你可以添加取消命令的功能,同时可以快速的增加新命令
3 解释器(Interpreter) - 类行为型模式
解释器: 在程序中通过解释另外一种语言来提供对复杂事务的处理
目的: 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子
应用:
在模式匹配中会用到,你可以在网上找到模式匹配实现的鼻祖 - Henry Spencer的代码了解.
同时在一些游戏或程序中也支持脚本, 如魔兽世界支持lua脚本
复杂的文法一般比较难维护,这时一般可以使用lex&yacc来实现(牺牲性能来实现功能)
4 迭代器(Iterator) - 对象行为型模式
迭代器: 不暴露对象的内部表示,而是提供另外方法访问聚合对象内各元素
目的: 提到一个方法顺序访问一个聚合对象中各个元素,而又不城暴露该对象的内部表示
应用: STL中各容器的迭代器
如果你想让用户访问对象内的数据,但是又不想让他们知道这些数据的存放方式的话,可以使用迭代器
5 中介者(Mediator) - 对象行为型模式
中介者:一系列的对象交互通过中介来通信而不是对象间直接通信
目的: 用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立的改变它们间的交互
应用: 一个系统中有多个对象它们相互关联,想降低耦合性
6 备忘录(Memento) - 对象行为型模式
备忘录: 用一个对象在不知道另外一个对象内部的情况下保存它的状态
目的: 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象外保存这个状态,后面可以把这个对象恢复到原先保存的状态
应用; 如果你想恢复一个对象的状态到之前某个状态, 那使用备忘录可能会好点
7 观察者(Observer) - 对象行为型模式
观察者: 多个对象可以订阅当前对象的更新事件通知
目的: 定义对象间一种一对多的依赖关系,当一个对象的状态发行改变时,所有依赖于它的对象都得到通知并被自动更新
实现: 参与者: 目标与观察者
目标提供注册与删除观察者的接口
观察者为需要关注的事件提供更新的接口
应用: 在Symbian中基本上每个事件都可以增加观察者,这样当事件发生时所有观察者都得到通知从而增加开发的灵活性
8 状态(State) - 对象行为型模式
状态: 对象在内部状态改变时改变它的行为
目的: 充许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类
应用; 不同状态下, 相同接口的行为不一样时可以用,可以减少子类数目
9 策略(Policy)
策略: 不同的策略有相同的接口从而使它们可以互换
目的: 定义一系列的算法,使它们一个个封装起来,并且它们可以相互替换,本模式使得算法可独立于使用它的客户而变化
10 模板方法(Template method) - 类行为模式
模板方法:把一个操作中不变的部分做为模板,可变的部分由子类完成
目的: 定义一个操作中算法的骨架, 而将一些步骤延迟到其子类中,模板方法使得子类可以不改变一个算法的结构
11 访问者(Visitor) - 对象行为模式
访问者: 通过接受访问者来扩展自己的接口
目的; 表示一个作用于某对象结构中的各元素的操作。它使你在不改变各元素的类的前提下作用于这些元素的新操作。
实现; 有两个对象:visitor与node
visitor提供visit接口,visit接口的参数可以是一个node或是这个node里面的一个对象.
node提供一个accept接口,它将接受一个访问者,并在这个接口里面调用这个访问者的visit函数
这样可以通过添加一个visitor接口来针对node里面的数据进行不同的操作,相当于添加了了node的接口
应用:
一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作污染这些对象的类. Visitor使得你可以将相关的操作集中起来定义在一个类中。
解决某个问题的方案
每个模式有四个特征:
模式名
问题
解决方案
效果
MVC的设计模式:
界面设计中经常会使用类的模型/视图/控制器 (Model/View/Controller) 这三个东西.
Model可以看成是一个对象, View是它的显示, Controller是它的输入的响应
设计的原则:
把易变的部分与不变的部分分开, 使程序易于扩展
让对象间的耦合度降低,使一个对象的修改不会影响另外一个对象
复用的要点:
1 对接口而不是对实现编程
优点是:
客户不须知道他们使用的对象的特定类型,只知道对象有期望的接口
客户不须知道他们使用的对象是用什么类来实现的, 只知道定义接口的抽象类
结果可以避免各系统的依赖关系
2 优先使用对象组合成不是类继承
继承是通过对父类进行具体化来实现功能,继承在编译时确定,并且继承知道父类的实现,使子类与父类的依赖关系很紧密, 所以后面如果想维护时不好修改
组合是组装或是组合对象来实现更复杂的功能, 组合时只需要知道对象的接口实现的功能,而不需要知道对象的具体实现,所以依赖更少
委托是有两个对象参与处理一个请求,接收请求的对象把操作委托给它的代理者. 它是组合的一种对例
3 参数化类型
参数化类型是定义一个类型时不指定该类型所使用到的其它所有类型,未指定的类型在使用时以参数提供,这就是c++中的模板
这个一般用于解决操作时步骤基本相同,只是类型不同的场合,想更多的理解可以看STL库
4 聚合与相识
聚合表示一个对象拥有另一个对象或是对另一个对象负责
相识则是一个对象仅知道另一个对象, 有时也叫"关联" 或 "引用"
相识比聚合的耦合性要弱
模式的分类;
可以分成三类:
创建型模式: 用于对象过程的模式
结构型模式: 用于把不同的类或对象组合起来实现更复杂的功能
行为型模式: 用于规定不同类或对象间的交互方法或是职责,与结构型模式不同的是行为型模式中的对象是平行的,它们是交互的关系,而在结构型中它们是组合的关系,并且可能是包含的关系
/*-----------------------------------------------------------------------------
*
* 创建型模式 (用户类或对象的创建过程的模式)
*
*-----------------------------------------------------------------------------*/
对象创建型模式: 这个模式用于创建新的对象
特点:
隐藏具体实现: 把具体类的信息封装起来
隐藏创建过程: 隐藏了这些类的实例是如何被创建与放在一起的, 系统只知道这些对象中由抽象类所定义的接口
1 抽象工厂(Abstract Factory) - 对象创建型模式
抽象工厂:
创建一批抽象类的对象的工厂
目的:
提供一个创建一系列相关或相互依赖对象的接口,
而无需指定它们具体的类
实现:
参与者: 工厂Factory, 产品Product
Product是一批抽象类, 定义了产品的接口
Factory提*生Product的方法
具体的Factory提*生实例化的Product的方法
例子:
如gvim在Windows或是Linux上,窗口外观不一样,
但是窗口的组成部分基本一样(如都有标题栏,菜单,编辑区等),
相同控件的功能基本一样(如菜单的功能), 并且控件间可能有关联
这可以定义标题栏,菜单, 编辑区的抽象类定义它们的功能, 然后定义一套接口产生这些抽象类
2 生成器(Builder) - 对象创建型模式
生成器:
使用导向器引导类的创建过程,为相同的类创建不同对象的方法
目的:
将一个复杂对象的构建与它的表示分离,
使得同样的构建过程可以创建不同的表示
实现:
参与者:导向者director与生成器builder.
builder在构造函数中只进行基本的功能,
同时提供了其它接口进行对象的初始化,
director引导builder的构造过程,
调用builder的构造函数与其它初始化函数来创建builder,
并返回builder对象
class Builder{
public:
Builder(); // 构造函数
void BuildPartA(); // 初始化函数,初始化到状态A
void BuildPartB(); // 初始化函数,初始化到状态B
...
};
class Director{
public:
...
Builder* CreateBuilder1(){ // 引导生成的对像的构建过程
Builder* p = new Builder;
p->BuildPartA();
return p;
}
Builder* CreateBuilder2(){ // 引导生成的对像的构建过程
Builder* p = new Builder;
p->BuildPartB();
return p;
}
Builder* CreateBuilder3();
};
从上面的例子可以看出, builder只是提供基本的构造函数. 而具体生成怎样的builder由director决定. director封装了builder构造过程
builder模式把构造代码与表示代码分开, 因为builder的构造函数中并没有进行完整的构造, builder的构造是在director的CreateBuilderX中进行的. 你可以对它进行更多的订制.
我想这个应该适合一个对象可以有多个状态表示的时候. 如房间类, 假设内部的物品是一样的, 但不同的摆设会形成不同的房间. 而builder模式中使用director就可以为房间类导向而为每个房间生成不同的对象.
3 工厂方法(Factory Method) - 对象创建型模式
工厂方法:
creator的子类提供方法生产product对象
目的:
定义一个用于创建对象的接口,让子类决定实例化哪个类.Factory method使一个类的实例化延迟到子类
实现:
需要两个参与者:创建者creator与产品product,
1 product 对象定义基本的接口,
2 creator 定义创建 product 的接口.
3 creator 的子类实例化创建 product 的接口.
应用:
一般,如果creator与product有联系的话, 会使用这种方法.如在界面开发中的程序文档关系(Application,document,这个在Windos开发中经常会看到).
4 原型(ProtoType) - 对象创建型模式
原型:
通过调用原型的Clone方法创建新的对象,
新的对象不需要再进行其它特别的初始化(就达到与原型相同的状态)
目的:
用原型实例指定创建对象的种类, 并且通过拷贝这些原型创建新的对象
实现:
原型类提供一个Clone操作可以用来Clone自身状态
原型对象可能经过特别的初始化后才达到当前状态, 但下一个对象直接调用原型对象的Clone就可以直接达到这个状态而不需要再进行特别的初始化
应用:
这个方法一般用在系统中有几类不同的对象组成,这些对象区别的只是它们的状态, 如音符
5 单件(Singleton) - 对象创建型模式
单件:
类的实例只有并且只会有一个
目的:
保证类只有一个实例, 并提供一个访问它的全局访问点
实现:
c++中声明类的构造函数为非public的, 并且提供一个friend方式或是类的static方法来创建实例.
应用:
如果系统中一个类有多个实例会有问题, 就使用这个方法吧, 这样可以避免后面维护的人产生错误
/*-----------------------------------------------------------------------------
*
* 结构型模式
*
*-----------------------------------------------------------------------------*/
结构型模式: 通过组合类或对象来获得更大的结构并且得到新的功能
结合类的叫类对象结构型模式
结合对象的叫对象结构型模式
1 适配器(Adapter) - 类对象结构型模式
适配器:
用一个包装器Wrapper封装另外一个类并提供用户所希望的接口
目的:
将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原来由于接口不兼容而不能一起工作的那些类可以工作
实现:
定义一个新类Wrapper封装旧类,
新类通过调用旧类接口来提供用户希望的接口
2 桥接(Bridge) - 对象结构型模式
桥接:
类的抽象部分与实现部分都可以独立的变化
目的:
将抽象部分与它的实现部分分离, 使它们都可以独立的变化
原因;
当一个抽象可能会继承,
并且它的实现也有多种方式时,
它的抽象与实现都需要独立变化,
这时为了简化继承(而不是每个实现都有一个继承),
可以使用桥接的技术让实现也抽象化可以独立的变化,
而抽象部分也可以独立的变化
实现:
参与者:抽象Abstraction与实现Implementor
Abstraction定义抽象类的接口,并且维护一个指南Implementro类型对象的指针
Implementor定义实现类的接口, 该接口不一定要写Abstraction的接口一致. 一般来讲, Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作
作用: 如果你希望两个部分都可以独立变化的话, 那就用Bridge吧(一般是抽象有继承的条件下, 并且抽象的实现也需要变化的时候)
如果实现是固定的, 那直接使用继承就可以了不用Bridge
3 组合(Composite) - 对象结构型模式
组合:
操作时不管是对象还是对象的组合都一致同仁,如果是对象的组合的话对象的组合会把操作传到每个对象并返回一个最后的结果的
目的:
把对象组合成树形结构以表示"部分-整体" 的层次结构, 使用户对单个对象和组合对象的使用具有一致性
实现:
定义一个Component抽象类,为组合中的对象声明接口,声明一个接口用于访问和管理Component的子组件
Leaf表示叶节点对象,在组合中定义对象的行为
Composite定义有子部件的那些部件的行为,
并且存储子部件,同时实现与子部件相关的操作
Client通过Component接口操纵组合部件的对象
一个组件可以添加到另外一个组件中从而组成一棵树, 接收到请求时会把请求一层一层往下传直到叶子
解决的问题:
表示部分-整体观点,简化其它部分的操作代码
适用性;
想表示对象的部分-整体层次结构
想用户忽略组合对象与单个对象的不同,用户将统一的使用组合结构中的所有对象
应用;
作者的例子是计算机报价单, 确实使用报价单的话最后对一个组合求价格更方便一些
装饰(Decorator) - 对象结构型模式
装饰:
对象A给对象B添加功能,并且对象A提供的接口与对象B一样
目的:
动态的给一个对象添加一些额外的职责,就增加功能来说,装饰比生成子类更灵活
实现: 参与者:组件Component与装饰者Decorator
Decorator维持一个指向Component对象的指针, 并定义一个与Component接口一致的接口(一般继承相同的抽象类),它将给Component动态的添加职责
应用:
想给一个类扩展一些功能,但是又不想产生子类的时候
在不影响其它对象的情况下以动态透明的方式给单个对象添加职责
处理那些可以撤消的职责
4 外观(Facade) - 对象结构型模式
外观:
为一组接口提供一个一致的界面
目的:
为子系统中一组接口提供一个一致的界面.
Facade定义了一个高层接口, 这个接口使得这一子系统更加容易使用
原因:
把一个系统分成若干个子系统有利于降低系统的复杂性,
为了让子系统间的通信与相互依赖关系达到最小,
使用外观的方法可以为子系统提供一个单一而简单的界面
结果:
让这个子系统与外界的耦合性最小, 并且这组子系统更容易使用
其实就像是库的接口那样,它们提供了一个简单的功能给外面
5 享元(Flyweight) - 对象结构型模式
享元:
不同场景中出现同一个对象,那可以把它们只看成一个对象的共享,场景中只存储它们的外部状态与对这个对象的引用
目的:
运用共享技术有效的支持大量细粒度的对象
实现:
实现一般包括flyweight与flyweightfactory,client三个部分
flyweight是一个共享对象, 它会同时出现在多个场景(context), 并且每个场景中都可以做为一个独立的对象. 但是, 它不能对它所运行的场景做出任何假设。
为了实现flyweight对象, 可以把flyweight的状态分成内部状态与外部状态, 独立于场景的就叫内部状态,flyweight只保存内部状态. 与场景相关的就叫外部状态, 用户在调用时把外部状态传给Flyweight
flyweightfactory创建并管理flyweight对象
client维持对flyweight的引用,并且存储一个或多个flyweight的外部状态
例子:
如一个字处理器,它的享元是每个字符, 内部状态是字符值,外部状态是这个字的位置,大小等
作用: 理论就是如果一个对象需要在多个地方出现,并且只有状态不同时,可以使用享元的办法把内部状态保存在享元中,外部状态在调用这个对象时传入
可以减少系统中对象的数目
6 代理(Proxy) - 对象结构型模式
代理: 控制对另外一个对象的访问
目的; 为其它对象提供一个代理以控制对这个对象的访问
实现: 跟经济人的意思差不多, 也就是因为某种原因而不想让其它人直接访问主角而采取的一种措施
/*-----------------------------------------------------------------------------
*
* 行为模式
*
*-----------------------------------------------------------------------------*/
行为模式: 描述对象或类间行为的模式
行为类模式: 使用继承机制在类间分派行为
行为对象模式: 使用对象复合而不是继承来实现:
1 一组对等的对象怎样想到协作以完成其中任一个对象都无法完成的任务
2 把行为封状在一个对象中并将请求指派给它
1 职责链(Chain of responsibility) - 对象行为型模式
职责链:
多个对象连成一条链, 每个请求都在这条链中从头到尾传送直到有对象处理它为止
目的:
把发送者与接收者的耦合去掉
使多个对象都有机会处理请求。装这些对象连成一条链,并沿着这条链发送请求,直到有一个对象处理它为止。
应用:
多个对象可以处理一个请求,哪个对象处理该请求运行时自动确定
想在不明确指定接收者的情况下,向多个对象中的一个提交请求
可处理一个请求的对象集合应该被动态指定
2 命令(Command) - 对象行为型模式
命令: 每个请求都是一个对象,对于过程语言则是每个请求都有一个回调关联
目的: 将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,及支持可撤消的操作
功能: 你可以进行命令排队, 你可以添加取消命令的功能,同时可以快速的增加新命令
3 解释器(Interpreter) - 类行为型模式
解释器: 在程序中通过解释另外一种语言来提供对复杂事务的处理
目的: 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子
应用:
在模式匹配中会用到,你可以在网上找到模式匹配实现的鼻祖 - Henry Spencer的代码了解.
同时在一些游戏或程序中也支持脚本, 如魔兽世界支持lua脚本
复杂的文法一般比较难维护,这时一般可以使用lex&yacc来实现(牺牲性能来实现功能)
4 迭代器(Iterator) - 对象行为型模式
迭代器: 不暴露对象的内部表示,而是提供另外方法访问聚合对象内各元素
目的: 提到一个方法顺序访问一个聚合对象中各个元素,而又不城暴露该对象的内部表示
应用: STL中各容器的迭代器
如果你想让用户访问对象内的数据,但是又不想让他们知道这些数据的存放方式的话,可以使用迭代器
5 中介者(Mediator) - 对象行为型模式
中介者:一系列的对象交互通过中介来通信而不是对象间直接通信
目的: 用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立的改变它们间的交互
应用: 一个系统中有多个对象它们相互关联,想降低耦合性
6 备忘录(Memento) - 对象行为型模式
备忘录: 用一个对象在不知道另外一个对象内部的情况下保存它的状态
目的: 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象外保存这个状态,后面可以把这个对象恢复到原先保存的状态
应用; 如果你想恢复一个对象的状态到之前某个状态, 那使用备忘录可能会好点
7 观察者(Observer) - 对象行为型模式
观察者: 多个对象可以订阅当前对象的更新事件通知
目的: 定义对象间一种一对多的依赖关系,当一个对象的状态发行改变时,所有依赖于它的对象都得到通知并被自动更新
实现: 参与者: 目标与观察者
目标提供注册与删除观察者的接口
观察者为需要关注的事件提供更新的接口
应用: 在Symbian中基本上每个事件都可以增加观察者,这样当事件发生时所有观察者都得到通知从而增加开发的灵活性
8 状态(State) - 对象行为型模式
状态: 对象在内部状态改变时改变它的行为
目的: 充许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类
应用; 不同状态下, 相同接口的行为不一样时可以用,可以减少子类数目
9 策略(Policy)
策略: 不同的策略有相同的接口从而使它们可以互换
目的: 定义一系列的算法,使它们一个个封装起来,并且它们可以相互替换,本模式使得算法可独立于使用它的客户而变化
10 模板方法(Template method) - 类行为模式
模板方法:把一个操作中不变的部分做为模板,可变的部分由子类完成
目的: 定义一个操作中算法的骨架, 而将一些步骤延迟到其子类中,模板方法使得子类可以不改变一个算法的结构
11 访问者(Visitor) - 对象行为模式
访问者: 通过接受访问者来扩展自己的接口
目的; 表示一个作用于某对象结构中的各元素的操作。它使你在不改变各元素的类的前提下作用于这些元素的新操作。
实现; 有两个对象:visitor与node
visitor提供visit接口,visit接口的参数可以是一个node或是这个node里面的一个对象.
node提供一个accept接口,它将接受一个访问者,并在这个接口里面调用这个访问者的visit函数
这样可以通过添加一个visitor接口来针对node里面的数据进行不同的操作,相当于添加了了node的接口
应用:
一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作污染这些对象的类. Visitor使得你可以将相关的操作集中起来定义在一个类中。