【设计模式学习笔记】代理模式、装饰模式和适配器模式案例详解(C++实现)
目录
一、代理模式
1. 什么是代理模式
Proxy Pattern,代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理来控制对这个对象的访问。所谓的代理,就是指一个具有与被代理对象(代理元)相同接口的类,客户端只有通过Proxy来实现与被代理类的交互,并且在交互过程中 ,代理可以增加其它操作。
代理可以分为多个种类
- 远程代理:可以隐藏一个对象在不同地址空间的事实,可以理解为将工作委托给远程的代理(服务器)来完成;
- 虚拟代理:通过代理来存放需要很长时间实例化的对象;
- 安全代理:用来控制真实对象的访问权限;
- 智能引用:当调用真实对象时,代理处理另外一些事;
在代理模式中,有四种角色
- 抽象主题角色subject:真实主题与代理主题的共同接口,并供客户端使用;
- 真实主题角色RealSubject: 定义了代理角色所代表的真实实体。
- 代理主题角色Proxy:含有一个引用,使得代理可以访问真实主题角色,并提供一个和抽象主题角色相同的接口,以便于代理角色可以用来替代真是主题角色。代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象,也就是说代理可以执行真是主题角色之外的其他操作。
2. 代理模式的案例
假设现在有一个客户需要买车,他可以去实体店买,也可以在瓜子二手车买,瓜子二手车就是一个代理,它可以销售实体店的车,并提供节假日打折活动。
#include <iostream>
using namespace std;
//抽象主题角色
class CarStore
{
public:
virtual void sail_Car() = 0;
};
//真实主题角色
class ReilCarStore : CarStore //实际汽车销售店铺
{
public:
virtual void sail_Car()
{
cout << "实体店铺直接卖出汽车" << endl;
}
};
//代理
class GZproxy : public CarStore //瓜子二手车是一个代理商
{
public:
/*
virtual void sail_Car()
{
cout << "瓜子二手车直营(自己卖)" << endl;
}
*/
virtual void sail_Car()
{
ReilCarStore cartore;
cartore.sail_Car(); //表面是瓜子二手车卖车,实际上销售的是实体店的车
discount(); //扩充了实体店卖车的形式和功能
}
void discount()
{
cout << "双11活动打折" << endl;
}
};
//客户
int main()
{
GZproxy dd;
dd.sail_Car();
system("pause");
return 0;
}
二、装饰模式
1. 什么是装饰模式
Decorator Pattern,装饰模式,也叫做包装模式,是结构型模式的一种。装饰模式动态的给一个对象增加了额外的功能,并且这种扩充功能的方式对客户是透明的。装饰模式的具体实现就是把一些功能封装在一个个单独的子类中,并让这些子类包含要被装饰的对象,当有需要功能扩充的时候,客户就可以有选择的通过装饰类来装饰某个对象。装饰模式可以理解为继承的一种替代,他比继承更加灵活,客户可以根据需要自由选择。
- Component:被装饰的主体,定义了一个对象接口,可以给这些对象增加装饰功能;
- ConcreteComponent:具体的对象,继承于Component;
- Decorator:装饰者,继承于Component并从Component类的外部完成对Component类功能的扩充,并且Component类并不需要知道装饰者的存在;
2. 装饰模式案例
假设我们要设计一个游戏角色Hero,它最初只有跑步的技能,但是通过升级可以完成功能扩充,比如飞行,发射激光等。
首先定义一个Component角色,也就是要被装饰的主题的抽象接口。
class Hero
{
public:
virtual void show_skill() = 0;
};
然后定义一个具体的要被装饰的对象ConcreteComponent
//初始的英雄:只能跑
class runHreo : public Hero
{
public:
void run_skill()
{
cout << "只能跑的超人" << endl;
}
virtual void show_skill()
{
run_skill();
}
};
最后添加两个装饰者,每个装饰者都可以完成对被装饰对象不同的功能扩充,一个装饰者可以为英雄角色扩充飞行技能,另一个装饰者可以为英雄角色扩充激光发射功能
//超人升级:新增了飞行技能
class flyHero : public Hero
{
private:
Hero* m_hero;
public:
flyHero(Hero* hero)
{
this->m_hero = hero;
}
void fly_skill()
{
cout << "拥有飞行技能" << endl;
}
virtual void show_skill()
{
this->m_hero->show_skill();
fly_skill();
}
};
//超人升级:可以发射激光
class laserHero : public Hero
{
private:
Hero* m_hero;
public:
laserHero(Hero* hero)
{
this->m_hero = hero;
}
void laser_skill()
{
cout << "可以发射激光" << endl;
}
virtual void show_skill()
{
this->m_hero->show_skill();
laser_skill();
}
};
最后是客户需求,首先我们让一个英雄角色从跑步到飞行再到激光发射,一步步的获取技能
int main()
{
//创建一个超人角色
Hero* myHero1 = NULL;
cout << "*********第一个英雄*********" << endl;
//初始功能只有跑
cout << "======初始形态======" << endl;
myHero1 = new runHreo;
myHero1->show_skill();
//功能增强:升级飞行技能
cout << "======第一次升级======" << endl;
Hero* myHero2 = new flyHero(myHero1);
myHero2->show_skill();
//再次升级:可以放大招
cout << "======第二次升级======" << endl;
Hero* myHero3 = new laserHero(myHero2);
myHero3->show_skill();
delete myHero1;
delete myHero2;
delete myHero3;
system("pause");
return 0;
}
然后我们在创建一个英雄角色,它可以直接获取激光功能
{
cout << "*********第二个英雄*********" << endl;
cout << "======初始形态======" << endl;
myHero1 = new runHreo;
myHero1->show_skill();
//直接获取激光技能
cout << "======升级======" << endl;
myHero3 = new laserHero(myHero1);
myHero3->show_skill();
//增强功能可以自由组合
}
通过这两个英雄角色我们可以看到,客户可以根据需求任意组合对待装饰对象的功能扩充。
三、适配器模式
1. 什么是适配器模式
Adapter Pattern,构造型模式之一,也叫做变压器模式和装饰模式都是一种包装模式(Wrapper),通过适配器模式可以改变现有类的接口形式。适配器模式可以将一个类的接口转换成客户希望的另一种形式的接口,使得原本因接口不兼容而无法工作的类可以一起工作,适用于双方都不适合修改的场景。
- Target:客户期待的接口,可以是抽象类或者接口;
- Adapter:适配器,对Target和Adaptee进行适配,通过在内部包装一个Adaptee对象,来把源接口转换成目标接口;
- Adaptee:适配者,也就是需要被适配的类;
2. 适配器模式案例
假设我们现在只有一个RS232标准的接口,但是客户需求一个TTL标准的接口,这时就可以通过一个适配器把RS232接口适配成TTL电平标准。
#include <iostream>
using namespace std;
//Target:客户需要一个TTL电平接口
class TTL
{
public:
virtual void get_ttl() = 0;
};
//Adaptee:现在只有一个RS232接口
class RS232
{
public:
void get_rs232()
{
cout << "RS232接口" << endl;
}
};
//Adapter:适配器
class adapter : public TTL
{
private:
RS232* m_232;
public:
adapter(RS232* m_232)
{
this->m_232 = m_232;
}
void adapter232_to_ttl()
{
cout << "适配器:将RS232转换为TTL" << endl;
}
virtual void get_ttl()
{
this->m_232->get_rs232();
adapter232_to_ttl();
cout << "ttl电平接口" << endl;
}
};
int main()
{
RS232* my232 = NULL;
adapter* ad = NULL;
//现有一个RS232电平接口
my232 = new RS232;
//需求是TTL接口,所以创建一个适配器
my232->get_rs232();
cout << "=========" << endl;
ad = new adapter(my232);
ad->get_ttl();
delete my232;
delete ad;
system("pause");
return 0;
}