设计模式学习[12]---观察者模式

文章目录

前言

这篇博客讲一下观察者模式,它属于行为型设计模式。

这个模式从名字上来说,其实也挺好理解。观察一个东西变不变,变了怎么样?大概就是监视某个变量发生改变,接着做出动作。

那具体是怎么样?往下看吧。

1.原理阐述

观察者模式:定义 了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式其实又称之为发布-订阅模式。

观察者模式一般针对以下情景:

\quad \quad 需要为某对象建立一种"通知依赖关系",当该对象的状态发生变化时,通过公共或广播的方式通知一系列相关对象,实现对象之间的联动。但这种一对多的对象依赖往往又会造成该对象与其相关的一些列对象之间一种特别紧密的耦合关系。通过使用观察者模式,可以弱化上述的一对多依赖关系,实现对象之间关系的松耦合。观察者模式在日常工作中往往会在不知不觉中被使用。

说一下个人理解,比较简单:观察者模式其实就是用一种状态,来控制多个与这个状态相关联的对象。状态变了,控制的对象做出反应。这个反应在C++中就是事件的订阅和发布。

C++的订阅与发布机制就是观察者模式的一种,下面是一个简单的订阅与发布的demo。

cpp 复制代码
#include <iostream>
#include <vector>
#include <functional>
 
class PubSub {
public:
    using Subscriber = std::function<void(const std::string&)>;
 
    void subscribe(const std::string& event, Subscriber subscriber) {
        subscribers[event].push_back(subscriber);
    }
 
    void publish(const std::string& event, const std::string& message) {
        for (const auto& subscriber : subscribers[event]) {
            subscriber(message);
        }
    }
 
private:
    std::unordered_map<std::string, std::vector<Subscriber>> subscribers;
};
 
int main() {
    PubSub pubsub;
 
    // 定义订阅者
    SubPub::Subscriber subscriber = [](const std::string& message) {
        std::cout << "Received message: " << message << std::endl;
    };
 
    // 订阅事件
    pubsub.subscribe("event1", subscriber);
 
    // 发布事件
    pubsub.publish("event1", "Hello, World!");
 
    return 0;
}

这个例子中,我们定义了一个PubSub类,它有一个subscribe方法来注册订阅者,以及一个publish方法来发布消息。我们使用std::unordered_map来存储订阅者,其中键是事件名称,值是一个std::vector的Subscriber对象。当发布事件时,我们遍历对应事件的所有订阅者并调用它们。

在main函数中,我们创建了一个PubSub实例,定义了一个订阅者,并且订阅了名为"event1"的事件。然后我们发布了这个事件,订阅者接收到消息后会打印出来。

2.举例

下面引用一下书上的例子来说明观察者模式。

九月底十月初,炒股真的是热火朝天。假设你在一个小公司中就职,老板不在的是时候,公司的同事上班摸鱼都喜欢炒股,但是毕竟是摸鱼,被发现上班时间炒股那影响可不是太好。于是就需要一个同事负责观察老板的动向,如果老板来了则告诉大家。这个同事一般为前台,因为她正对着门,能最先知道老板的进公司,有她负责观察并通知同事是最好的人选。

下面是一个简单的伪代码

cpp 复制代码
class Secretary
{
public:
	void Attach(StockObsever observer)
	{
		observers.Add(observer);
	}
	//通知
	void Notify()
	{
		//遍历同事列表,提醒同事
	}
private:
	std::list<StockObserver> observers;//同事列表
}
class StockObserver
{
public:
	StockObserver(stirng name,Secretary sub){.....};//构造函数
	void Update(){...};//得到前台的提醒,做出响应
private:
	std::string name;
	Secretary sub;
}
int main()
{
//创建通知者对象:前台
//将同事放到观察者对象的通知列表中
//发现老板回来,前台通知
//同事做出响应:停止摸鱼,继续工作
return 0;
}

对面上面的这个代码,我们可以看到类与类之间的耦合很严重。通知者需要知道观察者是谁,观察者需要知道通知者是谁。双向耦合,显然不符合我们软件设计的需要。

通知者也可能不止一个,比如前台被老板叫过去有事情,同事被老板发现了在摸鱼,那么老板无论是批评还是一笑而过,其实都有通知的作用,所以对于具体的通知者的相同行为,可以提取为一个接口类。同时,摸鱼的人可能不只是炒股票,也可能看NBA,刷手机等等。也就是说,观察者分为好几类,刚才提到的三种属于具体的观察者,那么对于共性的行为应该提取为一个抽象的类。

于是有了下面的一个类图:

cpp 复制代码
class Subject//抽象通知者类
{
public:
	void Attach(Observer observer);//添加观察者
	void Detach(Observer observer);//删除观察者
	void Notify();//通知
}
class Observer//抽象观察者类
{
public:
	Observer(stirng name,Subject sub){.....};//构造函数
	void Update(){...};//得到前台的提醒,做出响应
protected:
	std::string name;
	Secretary sub;
}
class Secretary:public Subject//具体通知者类:前台秘书
{
public:
	void Attach(Obsever observer)
	{
		observers.Add(observer);
	}
	void Detach(Observer observer){.....};//删除观察者
	//通知
	void Notify(){};//遍历同事列表,提醒同事
private:
	std::list<Observer> observers;//同事列表
}
class Boss:public Subject
{
public:
	void Attach(StockObsever observer)
	{
		observers.Add(observer);
	}
	void Detach(Observer observer){.....};//删除观察者
	//通知
	void Notify(){};//遍历同事列表,提醒同事
private:
	std::list<Observer> observers;//同事列表
}
int main()
{
//创建通知者对象:前台
//将同事放到观察者对象的通知列表中
//发现老板回来,前台通知
//同事做出响应:停止摸鱼,继续工作

//这里就是多态的思想了,具体代码不放了,看类图可以写。
	return 0;
}

总结

观察者模式很常用,属于行为型设计模式的一种。其实有点像是 《计算机组成原理》 《计算机组成原理》 《计算机组成原理》里面的中断方式,有事情了,喊一下CPU处理一下。这个观察者模式就是,有事情了通知一下观察者,处理一下。

相关推荐
山山而川粤30 分钟前
校园点餐系统|Java|SSM|JSP|
java·开发语言·后端·学习·mysql
梭七y1 小时前
记录学习《手动学习深度学习》这本书的笔记(五)
笔记·深度学习·学习
AI大模型训练家1 小时前
如何深入学习JVM底层原理?
java·开发语言·jvm·笔记·学习·spring·性能优化
码到成龚1 小时前
SQL server学习07-查询数据表中的数据(下)
数据库·sql·学习
虾球xz2 小时前
游戏引擎学习第49天
前端·学习·游戏引擎
纪伊路上盛名在3 小时前
使用AlphaFold3预测蛋白质三维结构及PyMol可视化1
服务器·人工智能·笔记·学习·知识图谱·学习方法
孔汤姆4 小时前
渗透测试学习笔记(五)网络
网络·笔记·学习
十月ooOO4 小时前
Docker 学习笔记(持续更新)
笔记·学习·docker
喝醉酒的小白4 小时前
KubeSphere
学习