文章目录
四、代理模式(结构型模式)
基本概念
proxy–代理
注意: 在很多设计模式中,都会用到 基类指针指向派生类对象,这是一种 面向对象编程(OOP) 的典型技巧,主要依赖于 多态(Polymorphism) 的特性。
代理模式:通过一个代理对象来控制实际对象的访问权限
例如:客户 <-> 助理(代理) <->老板(委托类:实际对象)
核心代码逻辑 – 重点
代理模式的结构
- Subject(抽象主题类):定义目标对象和代理对象的公共接口。
- RealSubject(真实主题类):定义了代理类所代表的目标对象的实际业务逻辑。
- Proxy(代理类):实现
Subject
接口,控制对RealSubject
对象的访问。在代理类中可以执行额外的操作,如日志记录、权限检查、缓存等。
如何写代理类
- 定义一个抽象的
Subject
类,这是目标对象和代理对象共享的接口。 - 定义一个
RealSubject
类,它实现了Subject
接口并实现了实际的业务逻辑。 - 定义一个
Proxy
类,它实现了Subject
接口,持有RealSubject
的引用,并在对真实对象的访问前后执行一些额外操作。
代码示例:
#include <iostream>
#include <memory>
using namespace std;
// 抽象类:视频站点 #1
class VideoSite
{
public:
virtual void freeMovie() = 0; // 免费电影
virtual void vipMovie() = 0; // VIP电影
virtual void ticketMovie() = 0; // 用券观看电影
virtual ~VideoSite() = default; // 虚析构函数以确保派生类正确析构
};
// 委托类:实际对象(IQIYI 视频站点) #2
class IQIYIVideoSite : public VideoSite
{
public:
virtual void freeMovie() { cout << "观看免费电影" << endl; }
virtual void vipMovie() { cout << "观看VIP电影" << endl; }
virtual void ticketMovie() { cout << "用券观看电影" << endl; }
};
// 代理类:免费用户代理 #3
class FreeProxy : public VideoSite
{
public:
FreeProxy() { Video = new IQIYIVideoSite(); }
~FreeProxy() { delete Video; }
// 通过代理类中重写的方法,来访问真正委托类的方法
virtual void freeMovie() { Video->freeMovie(); }
virtual void vipMovie() { cout << "您目前只是普通游客,需要升级成VIP,才能观看VIP电影" << endl; }
virtual void ticketMovie() { cout << "您目前没有券,需要购买电影券,才能观看电影" << endl; }
private:
VideoSite* Video; // 持有实际对象的指针 #4
};
// 代理类:VIP用户代理
class VipProxy : public VideoSite
{
public:
VipProxy() { Video = new IQIYIVideoSite(); }
~VipProxy() { delete Video; }
// 通过代理类中重写的方法,来访问真正委托类的方法
virtual void freeMovie() { Video->freeMovie(); }
virtual void vipMovie() { Video->vipMovie(); }
virtual void ticketMovie() { cout << "您目前没有券,需要购买电影券,才能观看电影" << endl; }
private:
VideoSite* Video; // 持有实际对象的指针
};
// 代理类:使用电影券用户代理
class TicketProxy : public VideoSite
{
public:
TicketProxy() { Video = new IQIYIVideoSite(); }
~TicketProxy() { delete Video; }
// 通过代理类中重写的方法,来访问真正委托类的方法
virtual void freeMovie() { Video->freeMovie(); }
virtual void vipMovie() { Video->vipMovie(); }
virtual void ticketMovie() { Video->ticketMovie(); }
private:
VideoSite* Video; // 持有实际对象的指针
};
// 这些都是通用的API接口,使用的都是基类的指针或者引用
void watchMovie(unique_ptr<VideoSite>& ptr)
{
ptr->freeMovie();
ptr->vipMovie();
ptr->ticketMovie();
}
int main() {
unique_ptr<VideoSite> p1(new FreeProxy); // 创建免费用户代理对象
unique_ptr<VideoSite> p2(new VipProxy); // 创建VIP用户代理对象
unique_ptr<VideoSite> p3(new TicketProxy); // 创建使用电影券用户代理对象
watchMovie(p1); // 观看电影,使用免费用户代理
cout << "===================" << endl;
watchMovie(p2); // 观看电影,使用VIP用户代理
cout << "===================" << endl;
watchMovie(p3); // 观看电影,使用电影券用户代理
return 0;
}
五、装饰器模式(结构型模式)-重点在于不修改原来的代码
基本概念
装饰器模式:可以动态地添加行为到对象中,而不需要修改类的定义
解决的问题: 为了增强现有类的功能 , 通过实现子类的方式, 重写接口, 是可以完成功能 扩展的, 但是代码 中 有太多子类 添加进来了
不使用装饰器, 原本的子类 都需要写 每个子类 对应的 新子类, 使用装饰器, 整体只需要写 一遍 新子类
代码核心逻辑
装饰器模式(Decorator Pattern)
核心思想: 装饰器模式的核心是:动态地给对象添加额外的功能。装饰器模式允许你在不修改对象原有代码的情况下,给对象增加新的行为或功能。它通过将对象包装在一个装饰器中,来扩展它的功能。
通俗的解释: 装饰器模式就像是在一个基础功能的物品上 加装不同的配件,每个配件都能给物品增加一些新功能,但你不需要修改物品本身。比如,你有一辆车,车本身就有基本功能(如行驶),而你可以选择性地添加空调、音响、座椅加热等配件,这些配件就像装饰器一样,给原车增加了新功能。–这就像抽象工厂, 每次工厂需要添加新的物件, 都要增加基类和派生类的 对应 虚函数
如何实现装饰器模式:
- 抽象组件基类(Component):定义基本功能的接口,所有装饰器和被装饰的对象都实现这个接口。
- 具体组件(ConcreteComponent):实现了基本功能的类,提供最基础的行为。
- 装饰器基类(Decorator):也实现了组件接口,但它在持有组件实例的同时,扩展了功能。
- 具体装饰器(ConcreteDecorator):继承装饰器类,提供实际的功能扩展。
总结:
装饰器模式允许你通过“包裹”对象来 动态地添加新功能,而不需要修改原始对象的代码。通过装饰器,你可以按需增加功能,且多个装饰器可以组合使用,形成多样的功能扩展。
代码示例
**代码示例(普通指针版本): ** – 可以使用 智能指针
#include <iostream>
#include <memory>
using namespace std;
// 抽象基类(组件)
class Car
{
public:
virtual void show() = 0;
virtual ~Car() = default; // 虚析构函数
};
// 三种汽车(具体组件)
class Bmw : public Car
{
public:
void show() override { cout << "这是一辆宝马汽车,配置有:基本配置"; }
};
class Audi : public Car
{
public:
void show() override { cout << "这是一辆奥迪汽车,配置有:基本配置"; }
};
class Benz : public Car
{
public:
void show() override { cout << "这是一辆奔驰汽车,配置有:基本配置"; }
};
// 装饰器基类
class CarDecorator : public Car
{
public:
CarDecorator(Car* car) : pCar(car) {}
virtual ~CarDecorator() { delete pCar; } // 确保释放被装饰的对象
protected:
Car* pCar;
};
// 装饰器1:定速巡航
class CruiseControl : public CarDecorator
{
public:
CruiseControl(Car* car) : CarDecorator(car) {}
void show() override
{
pCar->show();
cout << ", 定速巡航";
}
};
// 装饰器2:自动刹车
class AutoBrake : public CarDecorator
{
public:
AutoBrake(Car* car) : CarDecorator(car) {}
void show() override
{
pCar->show();
cout << ", 自动刹车";
}
};
// 装饰器3:车道偏离
class LaneDepartureWarning : public CarDecorator
{
public:
LaneDepartureWarning(Car* car) : CarDecorator(car) {}
void show() override
{
pCar->show();
cout << ", 车道偏离";
}
};
int main()
{
//Car* bmw = new Bmw(); // 只有基类配置
//修改1
//Car* p1 = new Bmw();
//p1 = new CruiseControl(p1); // 在基类配置上 添加了定速巡航
//修改2 这三种方式都可以
Car* p1 = new CruiseControl(new Bmw());
p1 = new AutoBrake(p1); // 继续添加了 自动刹车
p1 = new LaneDepartureWarning(p1); // 继续添加了 车道偏离
p1->show();
cout << endl;
delete p1; // 确保释放内存
Car* audi = new Audi();
Car* p2 = new AutoBrake(audi);
p2->show();
cout << endl;
delete p2; // 确保释放内存
Car* benz = new Benz();
Car* p3 = new LaneDepartureWarning(benz);
p3->show();
cout << endl;
delete p3; // 确保释放内存
return 0;
}
六、适配器模式(结构型模式)
基本概念
适配器模式:使不兼容的接口能够一起工作
电源转换插头、HDMI转VGA的线,这些都是适配器模式在生活中的例子
代码逻辑核心
适配器模式(Adapter Pattern)
核心思想: 适配器模式的核心是:通过一个适配器类来将不兼容的接口转换成可以使用的接口。它允许你将一个类的接口转换成客户端期望的另一个接口,从而解决接口不兼容的问题。适配器模式常用于连接不同的系统、模块或库,使它们能够互相工作。
通俗的解释: 适配器模式就像是你需要在中国用美国的电器插头,这时候你需要一个 插头转换器,它可以把美国的插头转换成中国的插座接口。适配器类就是这个转换器,它的作用是将一个类的接口转变成你所需要的接口,让两个原本不兼容的系统可以一起工作。
如何实现适配器模式:
- 目标接口(Target):定义客户端所期望的接口。
- 源接口(Adaptee):需要被适配的接口,通常是你无法直接修改或不符合你需求的接口。
- 适配器(Adapter):实现目标接口,将源接口转换为目标接口的适配器。
总结:
适配器模式通过适配器类将一个类的接口转换成另一个接口,从而使两个原本不兼容的接口可以一起工作。就像插头转换器一样,适配器在不修改源接口的情况下,适配成我们所需要的接口。
代码示例:
#include <iostream>
#include <memory>
using namespace std;
// VGA 接口类
class VGA
{
public:
virtual void play() = 0;
virtual ~VGA() = default;
};
// 具体的 VGA 投影仪
class VGAProjector : public VGA
{
public:
void play() override { cout << "通过 VGA 接口连接投影仪,进行视频播放" << endl; }
};
// HDMI 接口类
class HDMI
{
public:
virtual void play() = 0;
virtual ~HDMI() = default;
};
// 具体的 HDMI 投影仪
class HDMIProjector : public HDMI
{
public:
void play() override { cout << "通过 HDMI 接口连接投影仪,进行视频播放" << endl; }
};
// 适配器类,将 VGA 接口转换为 HDMI 接口
class VGAToHDMIAdapter : // VGA 接口类
class VGA
{
public:
virtual void play() = 0;
virtual ~VGA() = default;
};
// 具体的 VGA 投影仪
class VGAProjector : public VGA
{
public:
void play() override { cout << "通过 VGA 接口连接投影仪,进行视频播放" << endl; }
};
// HDMI 接口类
class HDMI
{
public:
virtual void play() = 0;
virtual ~HDMI() = default;
};
// 具体的 HDMI 投影仪
class HDMIProjector : public HDMI
{
public:
void play() override { cout << "通过 HDMI 接口连接投影仪,进行视频播放" << endl; }
};
// 适配器类,将 VGA 接口转换为 HDMI 接口
class VGAToHDMIAdapter : public VGA
{
public:
VGAToHDMIAdapter(HDMI* p) : pHdmi(p) {}
void play() override { pHdmi->play(); } // 该方法相当于转换头, 做不同接口的 信号转换
private:
HDMI* pHdmi;
};
// 电脑类,只支持 VGA 接口
class Computer
{
public:
void playVideo(VGA* pVGA) { pVGA->play(); }
};
int main() {
// 创建 Computer 对象
Computer* computer = new Computer();
// 通过 VGA 接口连接投影仪
VGAProjector* vgaProjector = new VGAProjector();
computer->playVideo(vgaProjector);
// 通过 HDMI 接口连接投影仪,使用适配器
HDMIProjector* hdmiProjector = new HDMIProjector();
VGAToHDMIAdapter* adapter = new VGAToHDMIAdapter(hdmiProjector);
computer->playVideo(adapter);
// 手动释放所有动态分配的内存
delete adapter;
delete hdmiProjector;
delete vgaProjector;
delete computer;
return 0;
}
{
public:
VGAToHDMIAdapter(HDMI* p) : pHdmi(p) {}
void play() override { pHdmi->play(); }
private:
HDMI* pHdmi;
};
// 电脑类,只支持 VGA 接口
class Computer
{
public:
void playVideo(VGA* pVGA) { pVGA->play(); }
};
int main() {
// 创建 Computer 对象
Computer* computer = new Computer();
// 通过 VGA 接口连接投影仪
VGAProjector* vgaProjector = new VGAProjector();
computer->playVideo(vgaProjector);
// 通过 HDMI 接口连接投影仪,使用适配器
HDMIProjector* hdmiProjector = new HDMIProjector();
VGAToHDMIAdapter* adapter = new VGAToHDMIAdapter(hdmiProjector);
computer->playVideo(adapter);
// 手动释放所有动态分配的内存
delete adapter;
delete hdmiProjector;
delete vgaProjector;
delete computer;
return 0;
}
七、观察者模式(行为型模式)
基本概念
行为型模式: 主要关注 对象之间的通信
观察者模式,又名发布-订阅模式或事件监听器模式,主要关注对象之间的一对多依赖关系。当一个对象(称为主题或被观察者)的状态发生改变时,所有依赖于它的对象(称为观察者)都会收到通知并自动更新
使用案例: 一组数据对象 => 通过这一组数据 => 曲线图(对象1)/柱状图(对象2)
当数据对象 改变时, 其他对象应该 接到通知
代码核心逻辑
观察者模式(Observer Pattern)
核心思想:
观察者模式的核心是:当一个对象的状态发生变化时,所有依赖它的对象都会收到通知,并自动更新。 这样可以让多个对象之间保持同步,而不需要它们直接相互引用,提高了系统的解耦性。
通俗解释:
观察者模式就像是 微信公众号订阅。
- 公众号(被观察者)发布新文章时,会通知所有订阅它的用户(观察者)。
- 订阅者(观察者)可以随时关注(添加到列表)或取消关注(从列表移除)。
- 当公众号有新内容时,所有订阅者都会收到通知,而公众号本身不需要知道每个订阅者的具体信息。
如何实现观察者模式?
- 被观察者(Subject):定义一个对象,它持有观察者列表,并提供添加、删除观察者的方法,同时定义通知观察者的方法。
- 观察者(Observer):定义一个接口,所有具体观察者实现该接口,并提供更新方法,当被观察者状态改变时,这些方法会被调用。
- 具体被观察者(ConcreteSubject):实现
Subject
接口,维护观察者列表,并在状态改变时通知所有观察者。 - 具体观察者(ConcreteObserver):实现
Observer
接口,在update()
方法中接收通知并进行相应处理。
代码示例:
#include <iostream>
#include <memory>
#include <unordered_map>
#include <list>
using namespace std;
// 观察者抽象类
class Observer
{
public:
// 处理消息的接口
virtual void handle(int msgid) = 0;
virtual ~Observer() = default;
};
// 第一个观察者实例:对消息1和消息2感兴趣
class Observer1 : public Observer
{
public:
void handle(int msgid) override
{
switch (msgid)
{
case 1:
cout << "Observer1 received message 1" << endl;
break;
case 2:
cout << "Observer1 received message 2" << endl;
break;
default:
cout << "Observer1 received unknown message" << endl;
break;
}
}
};
// 第二个观察者实例:对消息2感兴趣
class Observer2 : public Observer
{
public:
void handle(int msgid) override
{
if (msgid == 2)
{
cout << "Observer2 received message 2" << endl;
}
else {
cout << "Observer2 received unknown message" << endl;
}
}
};
// 第三个观察者实例:对消息1和消息3感兴趣
class Observer3 : public Observer
{
public:
void handle(int msgid) override
{
switch (msgid)
{
case 1:
cout << "Observer3 received message 1" << endl;
break;
case 3:
cout << "Observer3 received message 3" << endl;
break;
default:
cout << "Observer3 received unknown message" << endl;
break;
}
}
};
// 主题类--被观察者
class Subject {
public:
// 添加观察者
void addObserver(Observer* observer, int msgid)
{
observers[msgid].push_back(observer);
//相当于
/*auto it = observers.find(msgid);
if (it != observers.end())
{
it->second.push_back(observer);
}
else
{
list<Observer*> lis;
lis.push_back(observer);
observers.insert({ msgid, lis });
}*/
}
// 通知观察者
void notifyObservers(int msgid)
{
auto it = observers.find(msgid);
if (it != observers.end())
for (Observer* observer : it->second)
observer->handle(msgid);
}
private:
unordered_map<int, list<Observer*>> observers; // list是观察者列表, 因为是多个,按消息ID分类
};
int main() {
Subject subject; // 主题
Observer* p1 = new Observer1(); //观察者们
Observer* p2 = new Observer2();
Observer* p3 = new Observer3();
// 注册观察者到不同的消息ID
subject.addObserver(p1, 1);
subject.addObserver(p1, 2);
subject.addObserver(p2, 2);
subject.addObserver(p3, 1);
subject.addObserver(p3, 3);
int msgid = 0;
while (true)
{
cout << "输入消息ID (-1 退出): ";
cin >> msgid;
if (msgid == -1)
break;
subject.notifyObservers(msgid);
}
// 清理内存
delete p1;
delete p2;
delete p3;
return 0;
}