代理模式
代理模式的定义:为其他对象提供了一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
在生活中 代理模式的例子有很多 比如我们想要访问外网youtube 但是无法直接访问 就需要用到代理服务器 或者说当很多很同时向一个网页发起请求的时候会变得很卡 这时候可以在中间设置一个代理服务器处理延迟初始化和缓存查询结果的工作
#include <iostream>
using namespace std;
//代理模式: 提供一个代理来控制对其他对象的访问
//提供一个公共接口 来约束 代理系统和真实系统必须都包含run()方法
class AbstractCommonInterface {
public:
virtual void run() = 0;
};
class MySystem : public AbstractCommonInterface{
public:
virtual void run() {
cout << "系统启动" << endl;
}
};
//提供一种代理来控制对其他对象的访问
//必须要有权限的验证 不是所有人都能来启动我的系统 提供用户名和密码来验证
class MySystemProxy : public AbstractCommonInterface {
public:
MySystemProxy(string username, string password) {
this->mUsernmae = username;
this->mPassword = password;
pSystem = new MySystem;
}
bool checkUsernameAndPassword() {
if (mUsernmae == "admin" && mPassword == "admin") {
return true;
}
return false;
}
virtual void run() {
if (checkUsernameAndPassword()) {
cout << "用户名和密码正确,验证通过" << endl;
this->pSystem->run();
}
else {
cout << "用户名或密码错误 权限不足" << endl;
}
}
~MySystemProxy() {
if (pSystem != NULL) {
delete pSystem;
}
}
private:
//代理类中有一个系统指针变量
MySystem* pSystem;
string mUsernmae;
string mPassword;
};
void test01() {
MySystemProxy* proxy = new MySystemProxy("admin","admin");
proxy->run();
delete proxy;
proxy = new MySystemProxy("wrong","admin");
proxy->run();
delete proxy;
}
int main() {
test01();
return 0;
}
输出结果:
用户名和密码正确,验证通过
系统启动
用户名或密码错误 权限不足
外观模型
根据迪米特法则 如果两个类不必彼此直接通信 那么这两个类就不应该发生直接的相互作用。
Facade模式也叫外观模式 是由 GoF 提出的23种设计模式中的一种。Facade模式为一组具有类似功能的类群 比如类库,子系统等等,提供一个一致的简单的界面。这个一致的简单的界面也被称作facade。
外观模式案例:
根据类图,实现家庭影院外观模式应用
实现KTV模式:电视打开,灯关掉,音响打开,麦克风打开,dvd打开;
实现游戏模式:电视打开,音响打开,游戏机打开。
#include <iostream>
using namespace std;
//外观模式案例
//电视机
class Television {
public:
void On() {
cout << "电视机打开..." << endl;
}
void Off() {
cout << "电视机关闭..." << endl;
}
};
//灯
class Light {
public:
void On() {
cout << "灯打开..." << endl;
}
void Off() {
cout << "灯关闭..." << endl;
}
};
//音响
class Audio {
public:
void On() {
cout << "音响打开..." << endl;
}
void Off() {
cout << "音响关闭..." << endl;
}
};
//麦克风
class Microphone {
public:
void On() {
cout << "麦克风打开..." << endl;
}
void Off() {
cout << "麦克风关闭..." << endl;
}
};
//DVDplayer
class DVDplayer {
public:
void On() {
cout << "DVD打开..." << endl;
}
void Off() {
cout << "DVD关闭..." << endl;
}
};
//游戏机
class Gamemachine {
public:
void On() {
cout << "游戏机打开..." << endl;
}
void Off() {
cout << "游戏机关闭..." << endl;
}
};
//KTV模式
class KTVMode {
public:
KTVMode() {
pTv = new Television;
pLight = new Light;
pAudio = new Audio;
pMicrophone = new Microphone;
pDVD = new DVDplayer;
}
void onKTV() {
pTv->On();
pLight->Off();
pAudio->On();
pMicrophone->On();
pDVD->On();
}
void offKTV() {
pTv->Off();
pLight->On();
pAudio->Off();
pMicrophone->Off();
pDVD->Off();
}
~KTVMode() {
delete pTv;
delete pLight;
delete pAudio;
delete pMicrophone;
delete pDVD;
}
public:
Television* pTv;
Light* pLight;
Audio* pAudio;
Microphone* pMicrophone;
DVDplayer* pDVD;
};
void test01() {
KTVMode* ktv = new KTVMode;
ktv->onKTV();
}
int main() {
test01();
return 0;
}
输出结果:
电视机打开...
灯关闭...
音响打开...
麦克风打开...
DVD打开...
适配器模式
将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
生活中的适配器:
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
//适配器模式 将已经写好的接口 但是这个接口不符合需求
//将写好的接口转换成目标接口
//这个函数之前已经写好了
struct MyPrint {
void operator()(int v1, int v2) {
cout << v1 + v2 << " ";
}
};
//定义目标接口
class Target {
public:
virtual void operator()(int val) = 0;
};
//写适配器
class Adapter : public Target {
public:
Adapter(int param) {
this->param = param;
}
//这里有点像是卡了个BUG
//用一个参数来满足for_each函数对象要求
//但实际上的输出却是用之前写好了的两参数 刚好多了个功能可以加一个值
virtual void operator()(int val) {
print(val,param);
}
public:
MyPrint print;
int param;
};
//这里我们定义一个函数 返回一个适配器
//传入的参数作为适配器构造函数的初始值
Adapter MyBind2nd(int val) {
return Adapter(val);
}
int main() {
vector<int>v;
for (int i = 0; i < 10;i++) {
v.push_back(i);
}
//这里输出的结果为 10 11 12 13 14 .....都加了10
for_each(v.begin(), v.end(), MyBind2nd(10));
cout << endl;
return 0;
}
输出结果:
10 11 12 13 14 15 16 17 18 19
装饰模式
装饰模式又叫包装模式,通过一种对客户端透明的方式来扩展对象功能,是继承关系的一种补充。
装饰模式就是要把附加的功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择、按顺序的使用装饰功能包装对象。
#include <iostream>
using namespace std;
#include <list>
//装饰模式
//一般情况下 用继承实现类功能的拓展
//装饰模式 可以动态给一个类增加功能
//抽象英雄
class AbstractHero {
public:
virtual void showStatus() = 0;
public:
int HP;
int AT;
int DF;
};
//具体英雄
class HeroA : public AbstractHero {
public:
HeroA() {
HP = 0;
AT = 0;
DF = 0;
}
virtual void showStatus() {
cout << "血量:" << HP << endl;
cout << "攻击:" << AT << endl;
cout << "防御:" << DF << endl;
}
};
//当英雄穿上某个装饰物装备 那么他不是原来的英雄 但还是个英雄
class AbstractEquipment :public AbstractHero {
public:
AbstractEquipment(AbstractHero* hero) {
this->pHero = hero;
}
virtual void showStatus() {
}
public:
AbstractHero* pHero;
};
//装饰物衣服
class Cloth : public AbstractEquipment {
public:
Cloth(AbstractHero* hero) :AbstractEquipment(hero) {}
//增加额外功能
void AddCloth() {
cout << "穿上cloth装饰物 防御加30" << endl;
this->HP = this->pHero->HP;
this->AT = this->pHero->AT;
this->DF = this->pHero->DF + 30;
delete this->pHero;
}
virtual void showStatus() {
AddCloth(); //额外增加的功能
cout << "血量:" << HP << endl;
cout << "攻击:" << AT << endl;
cout << "防御:" << DF << endl;
}
};
//装饰物武器
class Weapon : public AbstractEquipment {
public:
Weapon(AbstractHero* hero) :AbstractEquipment(hero) {}
//增加额外功能
void AddWeapon() {
cout << "穿上weapon装饰物 攻击力加30" << endl;
this->DF = this->pHero->DF;
this->AT = this->pHero->AT;
this->HP = this->pHero->HP + 30;
delete this->pHero;
}
virtual void showStatus() {
AddWeapon();
cout << "血量:" << HP << endl;
cout << "攻击:" << AT << endl;
cout << "防御:" << DF << endl;
}
};
void test01() {
AbstractHero* hero = new HeroA;
hero->showStatus();
cout << "--------------------" << endl;
//给英雄穿上衣服装饰物
hero = new Cloth(hero);
hero->showStatus();
//给英雄装备武器装饰物
hero = new Weapon(hero);
hero->showStatus();
}
int main() {
test01();
}
输出结果:
血量:0
攻击:0
防御:0
--------------------
穿上cloth装饰物 防御加30
血量:0
攻击:0
防御:30
穿上weapon装饰物 攻击力加30
血量:30
攻击:0
防御:30
总结:这个模式是一个非常复杂的模式 首先穿装备英雄(AbstractEquipment)和没穿装备英雄(HeroA)都属于英雄 所以都继承了抽象英雄(AbstractHero) 在代码中我们首先创建了一个没有穿装备的英雄(HeroA) 然后用同一父类接口(AbstractHero)去新new一个穿装备的英雄(AbstractEquipment) 而这个穿装备的英雄又依赖于没穿装备的英雄 因为要从没床装备的英雄(HeroA)那拿到初始状态 也就是血量攻击防御都为0的状态
然后Cloth和Weapon在初始化列表中添加了父类(AbstractEquipment)的构造函数来输出化AbstractEquipment的成员变量 而AbstractEquipment的成员变量又是从HeroA那拿到的所以可以说这时候Cloth和Weapon在内部在修改HeroA的成员变量 也就是初始状态