施磊老师高级c++(六)

四、代理模式(结构型模式)

基本概念

proxy–代理

注意: 在很多设计模式中,都会用到 基类指针指向派生类对象,这是一种 面向对象编程(OOP) 的典型技巧,主要依赖于 多态(Polymorphism) 的特性。

代理模式:通过一个代理对象来控制实际对象的访问权限

例如:客户 <-> 助理(代理) <->老板(委托类:实际对象)

核心代码逻辑 – 重点

代理模式的结构

  • Subject(抽象主题类):定义目标对象和代理对象的公共接口。
  • RealSubject(真实主题类):定义了代理类所代表的目标对象的实际业务逻辑。
  • Proxy(代理类):实现 Subject 接口,控制对 RealSubject 对象的访问。在代理类中可以执行额外的操作,如日志记录、权限检查、缓存等。

如何写代理类

  1. 定义一个抽象的 Subject,这是目标对象和代理对象共享的接口。
  2. 定义一个 RealSubject,它实现了 Subject 接口并实现了实际的业务逻辑。
  3. 定义一个 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)

核心思想: 装饰器模式的核心是:动态地给对象添加额外的功能。装饰器模式允许你在不修改对象原有代码的情况下,给对象增加新的行为或功能。它通过将对象包装在一个装饰器中,来扩展它的功能。

通俗的解释: 装饰器模式就像是在一个基础功能的物品上 加装不同的配件,每个配件都能给物品增加一些新功能,但你不需要修改物品本身。比如,你有一辆车,车本身就有基本功能(如行驶),而你可以选择性地添加空调、音响、座椅加热等配件,这些配件就像装饰器一样,给原车增加了新功能。–这就像抽象工厂, 每次工厂需要添加新的物件, 都要增加基类和派生类的 对应 虚函数

如何实现装饰器模式:

  1. 抽象组件基类(Component):定义基本功能的接口,所有装饰器和被装饰的对象都实现这个接口。
  2. 具体组件(ConcreteComponent):实现了基本功能的类,提供最基础的行为。
  3. 装饰器基类(Decorator):也实现了组件接口,但它在持有组件实例的同时,扩展了功能
  4. 具体装饰器(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)

核心思想: 适配器模式的核心是:通过一个适配器类来将不兼容的接口转换成可以使用的接口。它允许你将一个类的接口转换成客户端期望的另一个接口,从而解决接口不兼容的问题。适配器模式常用于连接不同的系统、模块或库,使它们能够互相工作。

通俗的解释: 适配器模式就像是你需要在中国用美国的电器插头,这时候你需要一个 插头转换器,它可以把美国的插头转换成中国的插座接口。适配器类就是这个转换器,它的作用是将一个类的接口转变成你所需要的接口,让两个原本不兼容的系统可以一起工作。

如何实现适配器模式:

  1. 目标接口(Target):定义客户端所期望的接口。
  2. 源接口(Adaptee):需要被适配的接口,通常是你无法直接修改或不符合你需求的接口。
  3. 适配器(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)

核心思想:
观察者模式的核心是:当一个对象的状态发生变化时,所有依赖它的对象都会收到通知,并自动更新。 这样可以让多个对象之间保持同步,而不需要它们直接相互引用,提高了系统的解耦性。


通俗解释:

观察者模式就像是 微信公众号订阅

  • 公众号(被观察者)发布新文章时,会通知所有订阅它的用户(观察者)。
  • 订阅者(观察者)可以随时关注(添加到列表)或取消关注(从列表移除)。
  • 当公众号有新内容时,所有订阅者都会收到通知,而公众号本身不需要知道每个订阅者的具体信息

如何实现观察者模式?

  1. 被观察者(Subject):定义一个对象,它持有观察者列表,并提供添加、删除观察者的方法,同时定义通知观察者的方法。
  2. 观察者(Observer):定义一个接口,所有具体观察者实现该接口,并提供更新方法,当被观察者状态改变时,这些方法会被调用。
  3. 具体被观察者(ConcreteSubject):实现 Subject 接口,维护观察者列表,并在状态改变时通知所有观察者。
  4. 具体观察者(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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值