代理模式、适配器模式、装饰器模式
大约 6 分钟
代理模式、适配器模式、装饰器模式
代理模式、适配器模式、装饰器模式属于结构型设计模式,这些模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式
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;
}
