“设计模式”学习之五:桥接、外观、享元与代理(结构型)

一、桥接(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模式实现相似度不一。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值