结构型模型
代理模式
代理模式的定义
为其他对象提供一种代理以控制这个对象的访问,在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用
个人理解:就像是水果商店是水果工厂的代理商,我们去水果商店买水果,然后由水果商店来控制是否把水果工厂的水果卖给我们,卖多少
注意:我们代理与原服务端必须要有相同的接口,等代理端同意了客户端的请求就可以调用原服务端的接口,去实现这个目的
代理模式
优点:必须有权限验证,不是所有人都能启动我的启动,必须提供用户名和密码
#include <iostream>
using namespace std;
//提供一种代理来控制对其他对象的访问
class AbstraactCommonInterface {
public:
virtual void run() = 0;
};
//我已经写好的系统
class Mysystem :public AbstraactCommonInterface{
public:
virtual void run() {
cout << "系统启动..." << endl;
}
};
//必须有权限验证,不是所有人都能来启动我的启动,必须提供用户名和密码
class MysystemProxy :public AbstraactCommonInterface {
public:
//接受传入密码与用户
MysystemProxy(string username,string password) {
this->mUsername = username;
this->mPassword = mPassword;
}
bool checkUsernameAndPassword() {
if (mUsername == "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;
}
}
public:
Mysystem* pSystem;//该指针指向系统
string mUsername;
string mPassword;
};
void test01() {
MysystemProxy* proxy = new MysystemProxy("root","admin");
proxy->run();
}
int main() {
#if 0
//这样不行。是个人都能启动
Mysystem* system = new Mysystem;
system -> run();
#endif
//调用代理模式
test01();
return 0;
}
代理模式的举例
1、上外网
我们无法直接访问yutube,但是我们可以访问代理服务器,然后代理服务器会将我们的要求传给youtube服务端,然后将我们请求的传给我
优点:
1、能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
2、客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性。
缺点:
代理实现较为复杂。
装饰模式
装饰模式又叫包装模式,通过一种对客户端透明的方式来扩展对象功能,是继承关系的一种替代
装饰模式就是把要附加的功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择的、按顺序的使用装饰功能包装对象。
下面就是我们主体是英雄,然后装饰就是各种装备(装备其实就是对英雄的部分属性发生了改变,继承重写),这样只要我们把英雄作为参数传入装备类进行实例化,就像是英雄穿上了装备
#include <iostream>
using namespace std;
//一般情况下,用继承实现类的功能拓展
//装饰模式 可以动态给一个类增加功能
//抽象英雄
class AbstractHero {
public:
virtual void ShowStatus() = 0;
public:
int mHp;
int mMp;
int mAt;
int mDf;
};
//具体英雄
class HeroA :public AbstractHero {
public:
HeroA() {
mHp = 0;
mMp = 0;
mAt = 0;
mDf = 0;
}
virtual void ShowStatus() {
cout << "血量:" << mHp << endl;
cout << "魔法:" << mMp << endl;
cout << "攻击:" << mAt << endl;
cout << "防御:" << mDf << endl;
}
};
//英雄穿上某个装饰物 那么他还是个英雄
//装饰物
class AbstractEquipmet : public AbstractHero {
public:
AbstractEquipmet(AbstractHero* hero) {
this->pHero = hero;
}
virtual void ShowStatus() = 0;
public:
AbstractHero* pHero;
};
//狂徒
class KuangtuEquipment :public AbstractEquipmet {
public:
KuangtuEquipment(AbstractHero* hero) :AbstractEquipmet(hero) {}
//增加额外的功能
void AddKuangtu() {
cout << "英雄穿上狂徒之后..." << endl;
this->mHp = this->pHero->mHp;
this->mMp = this->pHero->mMp;
this->mAt = this->pHero->mAt;
this->mDf = this->pHero->mDf + 30;
delete this->pHero;
}
virtual void ShowStatus() {
AddKuangtu();
cout << "血量:" << mHp << endl;
cout << "魔法:" << mMp << endl;
cout << "攻击:" << mAt << endl;
cout << "防御:" << mDf << endl;
}
};
//无尽
class Wujing : public AbstractEquipmet {
public:
Wujing(AbstractHero* hero) :AbstractEquipmet(hero) {}
//增加额外的功能
void AddWujing() {
cout << "英雄穿上无尽之后..." << endl;
this->mHp = this->pHero->mHp;
this->mMp = this->pHero->mMp;
this->mAt = this->pHero->mAt + 80;
this->mDf = this->pHero->mDf;
delete this->pHero;
}
virtual void ShowStatus() {
AddWujing();
cout << "血量:" << mHp << endl;
cout << "魔法:" << mMp << endl;
cout << "攻击:" << mAt << endl;
cout << "防御:" << mDf << endl;
}
};
void test01() {
AbstractHero* hero = new HeroA;
hero->ShowStatus();
cout << "----------------------------" << endl;
//给裸奔的英雄穿上衣服后
hero = new KuangtuEquipment(hero);
hero->ShowStatus();
cout << "----------------------------" << endl;
//装备武器
hero = new Wujing(hero);
hero->ShowStatus();
}
int main() {
test01();
return 0;
}
优点:
1、对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。
2、可以通过一种动态的方式来扩展一个对象的功能,从而实现不同的行为。
3、可以对一个对象进行多次装饰。
4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无须改变,符合“开闭原则”。
缺点:
使用装饰模式进行系统设计时将产生很多小对象,大量小对象的产生势必会占用更多的系统资源,影响程序的性能。
外观模式
如果两个类不必彼此直接通信,那么这两个类就不应该发生直接的相互作用
总结:外观模式就是将复杂的子系统抽象到同一个接口进行管理,外界只需要通过此接口与子类系统进行交换,而不必要直接与复杂的子类系统进行交互
外观模式的案例
根据类图,实现家庭影院外观模式应用。
实现KTV模式:电视打开,灯关掉,音响打开,麦克风打开,dvd打开;
实现游戏模式:电视打开,音响打开,游戏机打开。
我们不需要去一个一个开关去打开,而是直接打开ktv模式直接就好了
#include <bits/stdc++.h>
using namespace std;
//电视机
class Televison {
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;
}
};
//DVD
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 KTVModel {
public:
KTVModel() {
//创建开关对象
pTv = new Televison;
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();
}
~KTVModel() {
delete pTv;
delete pLight;
delete pAudio;
delete pMicrophone;
delete pDVD;
}
public:
Televison* pTv;
Light* pLight;
Audio* pAudio;
Microphone* pMicrophone;
DVDPlayer* pDVD;
};
void test01() {
KTVModel* ktv = new KTVModel;//创建ktv模式对象
ktv->OnKtv();//打开ktv对象的开关
}
int main() {
test01();
system("pause");
return 0;
}
适配器模式
将一个5v 与 220 v 的连接在一起
将一个类的接口转换成客户希望的另一个接口。使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作
下面例子就是适配器继承目标的接口,然后将之作为一个类常用函数,组合起来,这个适配器就可以接受两个参数,这样就可以u原来的接口通信
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//适配器模式 就是将已经写好的接口,但是这个接口不符合需求
//将写好的接口转换成目标接口
//这函数我已经写好
struct Myprint{
void operator()(int v1,int v2)//第一个括号是重载的括号,第二个是传入参数
{
cout << v1 + v2 << endl;
}
};
//定义目标接口 我要是配偶 适配成什么样的,
//要适配成只能传一个参数的,适配for_each第三个参数的适用
class Target {
public:
virtual void operator()(int v) = 0;
};
//写适配器,先继承目标接口
class Adapater :public Target {
public:
Adapater(int param) {
this->param = param;
}
virtual void operator() (int v) {
print(v,param);
}
public:
Myprint print;
int param;
};
//MyBind2nd,原来param固定的10,现在提供一个方法改
Adapater MyBind2nd(int v) {
return Adapater(v);
}
int main(void) {
vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
}
//适配器模式的运用
//for_each()的第三个参数是个带一个参数的函数,但是Myprint需要两个参数
for_each(v.begin(),v.end(), MyBind2nd(10));
return 0;
}