跳至主要內容

代理模式、适配器模式、装饰器模式

张威大约 6 分钟c/c++设计模式

代理模式、适配器模式、装饰器模式

代理模式、适配器模式、装饰器模式属于结构型设计模式,这些模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式

1、代理模式

不是所有的客户都能访问到老板,老板的助理,即通过代理类,来控制实际对象的访问权限。

代理类和委托类是组合关系!!!

  • 客户是不能直接使用委托类的,因为委托类是包含所有功能的!(
  • 代理类也是从基类派生的()!客户是直接访问代理类的,代理类中有个抽象类的指针,指向为委托类的对象!(
  • 因为代理类和委托类都继承重写了基类的所有方法,因此代理类在成员方法中可以控制委托类的成员方法访问权限
#include <iostream>
#include <memory>
using namespace std;

/*
代理Proxy模式 : 通过代理类,来控制实际对象的访问权限
客户     助理Proxy     老板 委托类
*/
class VideoSite // #1 抽象类
{
public:
	virtual void freeMovie() = 0; // 免费电影
	virtual void vipMovie() = 0; // vip电影
	virtual void ticketMovie() = 0; // 用券观看电影
};

// 委托类 #2
class FixBugVideoSite : public VideoSite
{
public:
	virtual void freeMovie() // 免费电影
	{
		cout << "观看免费电影" << endl;
	}
	virtual void vipMovie() // vip电影
	{
		cout << "观看VIP电影" << endl;
	}
	virtual void ticketMovie() // 用券观看电影
	{
		cout << "用券观看电影" << endl;
	}
};

// 代理类 #3 代理FixBugVideoSite
class FreeVideoSiteProxy : public VideoSite
{
public:
	FreeVideoSiteProxy() { Video = new FixBugVideoSite(); }
	~FreeVideoSiteProxy() { delete Video; }
	virtual void freeMovie() // 免费电影
	{
		Video->freeMovie(); // 通过代理对象的freeMovie,来访问真正委托类对象的freeMovie方法
	}
	virtual void vipMovie() // vip电影
	{
		cout << "您目前只是普通游客,需要升级成VIP,才能观看VIP电影" << endl;
	}
	virtual void ticketMovie() // 用券观看电影
	{
		cout << "您目前没有券,需要购买电影券,才能观看电影" << endl;
	}
private:
	VideoSite* Video; // # 4 组合的方式
};

// 代理类 代理FixBugVideoSite
class VipVideoSiteProxy : public VideoSite
{
public:
	VipVideoSiteProxy() { pVideo = new FixBugVideoSite(); }
	~VipVideoSiteProxy() { delete pVideo; }
	virtual void freeMovie() // 免费电影
	{
		pVideo->freeMovie(); // 通过代理对象的freeMovie,来访问真正委托类对象的freeMovie方法
	}
	virtual void vipMovie() // vip电影
	{
		pVideo->vipMovie();
	}
	virtual void ticketMovie() // 用券观看电影
	{
		cout << "您目前没有券,需要购买电影券,才能观看电影" << endl;
	}
private:
	VideoSite* pVideo;	//组合的方式
};
// 这些都是通用的API接口,使用的都是基类的指针或者引用
void watchMovice(unique_ptr<VideoSite>& ptr)
{
	ptr->freeMovie();
	ptr->vipMovie();
	ptr->ticketMovie();
}
int main()
{
	unique_ptr<VideoSite> p1(new FreeVideoSiteProxy()); // #5 客户直接访问代理对象
	unique_ptr<VideoSite> p2(new VipVideoSiteProxy());

	watchMovice(p1);
	cout << "=============================" << endl;
	watchMovice(p2);

	return 0;
}

都提供了

2、装饰器模式

目的: 为了增强现有类的功能。

增加类的功能,还可以增加一个子类!(太麻烦)

  • 给每个车增加两个功能,需要增加6个类!
  • 为了增强现有类的功能,通过实现子类的方式,重写接口,是可以完成功能扩展的,但是代码中有太多的子类添加进来了

因此我们使用装饰器模式!

和代理模式很像,只不过装饰器会对装饰的对象进行功能的扩展!

#include <iostream>
#include <memory>
using namespace std;

/*
装饰器模式 Decorator
通过子类实现功能增强的问题:为了增强现有类的功能,通过实现子类的方式,
重写接口,是可以完成功能扩展的,但是代码中有太多的子类添加进来了
*/
class Car // 抽象基类
{
public:
	virtual void show() = 0;
};

// 三个实体的汽车类
class Bmw : public Car
{
public:
	void show()
	{
		cout << "这是一辆宝马汽车,配置有:基类配置";
	}
};
class Audi : public Car
{
public:
	void show()
	{
		cout << "这是一辆奥迪汽车,配置有:基类配置";
	}
};
class Benz : public Car
{
public:
	void show()
	{
		cout << "这是一辆奔驰汽车,配置有:基类配置";
	}
};

// 装饰器1  定速巡航
class ConcreteDecorator01 : public Car
{
public:
	ConcreteDecorator01(Car* p) :pCar(p) {}
	void show()
	{
		pCar->show();//原来的方法
		cout << ",定速巡航";//新添加的功能
	}
private:
	Car* pCar;
};
class ConcreteDecorator02 : public Car
{
public:
	ConcreteDecorator02(Car* p) :pCar(p) {}
	void show()
	{
		pCar->show();
		cout << ",自动刹车";
	}
private:
	Car* pCar;
};
class ConcreteDecorator03 : public Car
{
public:
	ConcreteDecorator03(Car* p) :pCar(p) {}
	void show()
	{
		pCar->show();
		cout << ",车道偏离";
	}
private:
	Car* pCar;
};
int main()
{
	Car* p1 = new ConcreteDecorator01(new Bmw());
	p1 = new ConcreteDecorator02(p1);
	p1 = new ConcreteDecorator03(p1);
	p1->show();
	cout << endl;

	Car* p2 = new ConcreteDecorator02(new Audi());
	p2->show();
	cout << endl;

	Car* p3 = new ConcreteDecorator03(new Benz());
	p3->show();
	cout << endl;

	return 0;
}

3、适配器模式

适配器模式: 让不兼容的接口可以在一起工作

举个例子:

  • 电脑 =》 投影到 =》 投影仪上
  • 常用的投影接口的类型有:VGA HDMI TypeC

假如我们有VGA接口的电脑, 刚好(TV)投影仪也是VGA接口(此时电脑上的视频可以直接投到投影仪上)

#include <iostream>
#include <string>
using namespace std;

/*
适配器模式:让不兼容的接口可以在一起工作
电脑  =》   投影到    =》   投影仪上   VGA  HDMI  TypeC

VGA接口的电脑, (TV)投影仪也是VGA接口
*/
class VGA // VGA接口类
{
public:
	virtual void play() = 0;
};
// TV01表示支持VGA接口的投影仪
class TV01 : public VGA
{
public:
	void play()
	{
		cout << "通过VGA接口连接投影仪,进行视频播放" << endl;
	}
};

// 实现一个电脑类(只支持VGA接口)
class Computer
{
public:
	// 由于电脑只支持VGA接口,所以该方法的参数也只能支持VGA接口的指针/引用
	void playVideo(VGA* pVGA)
	{
		pVGA->play();
	}
};
/*
方法1:换一个支持HDMI接口的电脑,这个就叫代码重构
方法2:买一个转换头(适配器),能够把VGA信号转成HDMI信号,这个叫添加适配器类
*/

// 进了一批新的投影仪,但是新的投影仪都是只支持HDMI接口
class HDMI
{
public:
	virtual void play() = 0;
};
class TV02 : public HDMI
{
public:
	void play()
	{
		cout << "通过HDMI接口连接投影仪,进行视频播放" << endl;
	}
};


// 由于电脑(VGA接口)和投影仪(HDMI接口)无法直接相连,所以需要添加适配器类
class VGAToHDMIAdapter : public VGA
{
public:
	VGAToHDMIAdapter(HDMI* p) :pHdmi(p) {}
	void play() // 该方法继承于VGA,实现中调用hdmi的play,相当于就是转换头,做不同接口的信号转换的
	{
		pHdmi->play();
	}
private:
	HDMI* pHdmi;
};
int main()
{
	Computer computer;
	//computer.playVideo(new TV01());
	computer.playVideo(new VGAToHDMIAdapter(new TV02()));
	return 0;
}