一、桥接(Bridge,别名“Handle/Body”)
1、引言
我们一般的理解是:基类定义抽象接口;子类继承并实现接口。而桥接则是利用组合引用的方式,将抽象接口类Abstaction的功能实现部分交给另一个具体实现类Implementor。
2、一般思路
下图中,抽象接口类的Operation()会将操作交给具体实现类的OpertionImp()函数。
3、典型代码
(1)在RefinedAbstaction类声明:
class RefinedAbstaction: public Abstaction
{
public:
RefinedAbstraction(Implementor * imp);
private:
Implementor * _imp;
}
(2)在构造函数RefinedAbstraction(Implementor * imp)中,this->_ imp = imp;
(3)在RefinedAbstraction::Operation()实现中调用,_ imp -> OperationImp ();
(4)在客户代码main()中:
Implementor* imp = new Concrete Implementor A();
Abstraction* abs = new RefinedAbstraction(imp);
abs->Operation(); //交由ImplementorA来实现
4、应用提示
桥接模式一般用于系统开始阶段,接口与实现分离的方式有助于分层结构化。系统高层只需要知道Implementor和Abstraction。而且,当改变实现时,不需要重新编译接口Abstraction和客户程序。
二、外观(Facade)
1、引言
通常我们会有意将系统划分成几个子系统,并且各子系统松耦合。外观模式可以为子系统提供一个干净简单的外观(高层接口),将子系统内部的多个类的复杂实现隐藏起来。这个缺省的外观对于大多用户已经足够,但若需要更多定制,也可越过外观层。
2、一般思路
下图中,Façade组合引用子系统中的各个类SubClassA/B,将客户的请求通过包装的操作OperationWrapped()传递给子系统的对象来实现。
若要进一步降低客户-子系统的耦合度,可以将Façade声明为抽象类,通过其具体子类来实现OperationWrapped()。
3、典型代码
(1)在Facade类声明:
class Facade
{
private:
SubClassA * _subA;
SubClassB * _subB;
}
(2)在构造函数Facade()中:
this->_subA = new SubClassA();
this->_subB = new SubClassB();
(3)在析构函数~Facade()中:
delete subA;
delete subB;
(4)在Facade::OperationWrapper()中:
this->_subA -> Operation();
this->_subB -> Operation();
(5)在客户代码main()中:
Facade* f = new Facade();
f->OperationWrapper();
4、应用提示
(1)Façade模式在实际的开发设计中是应用最广、最多的模式之一。
(2)通常仅需要一个Façade对象,故可结合单件Singleton模式。
三、享元(Flyweight,别名“蝇量”)
1、引言
如果系统中存在大量的轻量级对象(如文字编辑器中的字符对象),可以考虑引入享元模式,利用共享技术来节约存储空间。
2、一般思路
下图中,FlyweightFactory拥有一个对象池(本例由vector来实现,也可用hash表等进行有效管理)。客户通过GetFlyweight(key)来访问对象池:若池中已有对象key,则返回该对象;若没有,则创建一个ConcreteFlyweight对象返回给客户。UnshareConcreteFlyweight是无需共享的对象。客户调用Operation()并传递外部状态extrinsicState,控制对象的状态。
3、典型代码
// Flyweight.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <vector>
#include <iostream>
#include <conio.h>
#include <string>
using namespace std;
class Flyweight
{
public:
Flyweight(){}
virtual ~Flyweight(){}
virtual void Operation(const string extrinsicState) = 0;//接受客户的外部状态
};
class ConcreteFlyweight : public Flyweight
{
public:
char _intrinsicState;
ConcreteFlyweight(char intrinsicState)
{
this->_intrinsicState = intrinsicState;
cout<<intrinsicState<<" is created!"<<endl;
}
~ConcreteFlyweight(){}
char GetIntrinsicState()
{
return this->_intrinsicState;
}//返回内部状态变量
void Operation(const string extrinsicState)
{
if (!extrinsicState.empty())
{
cout<<"<"<<extrinsicState<<"> "<<_intrinsicState<<endl;
}
else
cout<<"<Normal> "<<_intrinsicState<<endl;
}
};
class FlyweightFactory
{
public:
//作为对象池,存贮共享的Flyweight对象,也可用hash表等其它结构
vector <ConcreteFlyweight *>_flyVector;
FlyweightFactory(){}
~FlyweightFactory(){}
Flyweight * GetFlyweight(char key)
{
//引入迭代器实现按顺序访问池中的各Flyweight对象
vector <ConcreteFlyweight *>:: iterator it = _flyVector.begin();
ConcreteFlyweight * flyTemp;
if (_flyVector.size() == 0)//当容器内无任何对象时,先push一个对象
{
flyTemp = new ConcreteFlyweight(key);
_flyVector.push_back(flyTemp);
return flyTemp;
}
for (; it != _flyVector.end(); it++)//遍历对象
{
if ((*it)->GetIntrinsicState() == key)//若存在
{
cout<<key<<" is already existed.."<<endl;
return *it;
}
flyTemp = new ConcreteFlyweight(key);
_flyVector.push_back(flyTemp);
return flyTemp;
}
}
};
int _tmain(int argc, _TCHAR* argv[])
{
FlyweightFactory * fac1 = new FlyweightFactory();
Flyweight *fly1 = fac1->GetFlyweight('a');
Flyweight *fly2 = fac1->GetFlyweight('b');
Flyweight *fly3 = fac1->GetFlyweight('a');
fly1->Operation("BigSize");
fly2->Operation("");
fly3->Operation("Rotated");
_getch();/*等待按键继续*/
return 0;
}
实例运行情况截图如下:
4、应用提示
(1)Flyweight模式通常和组成Composite模式结合,用共享叶节点的有向无环图实现逻辑上的分层结构。
(2)通常,最好用Flyweight来实现状态State和策略Strategy模式。
四、代理(Proxy,别名“Surrogate”)
1、引言
书中提到,代理有几种典型应用类型:
(1)远程代理Remote Proxy:为一个对象在不同地址空间提供局部代表。比如,欲用网络上的某对象,可以创建一个本地代理来完成操作。当网络不畅时,尤其管用。
(2)虚代理 Virtual Proxy:对于一个开销很大的对象(如一幅大图片),可应用一个代理来代替它,只在需要时实例化该对象。
(3)保护代理Protection Proxy:控制对被代理对象的访问。如,论坛中用户的不同权限。
(4)智能指引Smart Reference:取代简单指针,并在访问对象时附加操作。包括引用计数等。(引述:copy-on-write优化技术——用代理延迟拷贝过程,修改时拷贝;可参看《C++沉思录》第5章)
2、一般思路
下图为典型虚代理类图,代理Proxy负责创建实体对象RealSbject;同时应用引用将客户请求Request()交由实体对象实施。图中的OtherFuction()对于不同类型的代理含义不同:对于虚代理,可以缓存实体对象的附加信息(如图像尺寸)以便延迟访问它;对于远程代理,可以负责对请求编码;而保护代理,可检查请求是否具备权限。
3、典型代码
(1)在Proxy类声明:
class Proxy
{
private:
Subject * _sub;
}
(2)在构造函数Proxy ()中:
this->_ sub = 0;
(3)在析构函数~ Proxy ()中:
delete _sub;
(4)在Proxy :: Request()中:
Subject* s = new RealSubject();
s-> Request ();
(5)在客户代码main()中:
Proxy * pro = new Proxy();
pro -> Request();
4、应用提示
(1)Proxy与实体对象共同继承于Subject,实现相同接口;而适配器Adapter则提供一个与被适配对象Adaptee不同的接口。
(2)各种类型的Proxy模式与装饰Decorator模式实现相似度不一。