观察者模式(Observer模式)c++实现

什么是观察者模式?在回答这个问题之前,先看看这样一个场景。这段时间,疫情在全世界肆虐,很多人每天都会习惯性地用手机看数据的变化,数据有湖北省内外的对比,新增、死亡、治愈的对比,国内外的对比等等。根据数据的变化,手机的统计界面都会用曲线图或者饼状图呈现,然后用户就能很直观地看到数据的变化。其实这就是观察者模式的一个常见应用。

定义

“观察者模式(又被称为发布-订阅(Publish/Subscribe)模式),属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。”

解释一下,在前面的例子中,疫情数据可以看作主题对象,而统计界面呈现就是观察者。比如一个主题对象是意大利每天新增新冠感染人数,通过这个数据,统计界面可以显示两个曲线图,一个是每日新增曲线图,还有一个是累计感染人数曲线图,这两个曲线图会根据主题对象的变化而变化,依赖于同一个数据。当然,疫情数据远不止一个,这里只是将它简化有助于理解。

框架图

在这里插入图片描述
(1)Subject:抽象主题。它维护了一个观察者集合,可以有任意数量的观察者,抽象主题提供接口,可以增加和删除观察者对象。当被观察的数据发生变化时,通知所有的观察者更新自己。

(2)ConcreteSubject:抽象主题的具体实现。当被观察的数据发生变化时,通知所有的观察者更新自己。若这个主题表示某一个疫情数据,当疫情数据变化时,通知相应的统计图更新。

(3)Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。

(4)ConcrereObserver:抽象观察者的具体实现,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

为什么要要用到抽象类,实现类?其实是增加代码的复用性和降低耦合性,有利于后期的维护与拓展。抽象类定义了被观察者与观察者之间的“变化转移”,同时建立了一套触发机制,它将大的框架搭好了,根据需求的变化,如何更新与拓展,就由程序员自由发挥了。

例子

通过一个简单的例子来加深理解。

1、抽象观察者

#pragma once

class Watcher{
public:
	virtual void dosomething(int a) = 0;
};

2、具体观察者

定义了两个观察者Watcher1,Watcher2,它们的区别在于对数据的处理方式。

#pragma once
#include "Watcher.h"
#include <iostream>
class Watcher1 : public Watcher{
public:
	virtual void dosomething(int data) override{
		cout << "Watcher1:: " << data << endl;
	}
};
#pragma once
#include "Watcher.h"
#include <iostream>
class Watcher2 : public Watcher{
public:
	virtual void dosomething(int data) override{
		cout << "Watcher2:: " << data << endl;
	}
};

3、抽象主题

#pragma once
#include <list>
#include "Watcher.h"
class topic{
public:
	virtual void insertwach(Watcher*) = 0;
	virtual void remvovewatch(Watcher*) = 0;
	virtual void notify() = 0;
	list<Watcher*> m_watcher;
};

4、主题的实现

#pragma once
#include <list>
#include <windows.h>
#include "topic.h"
#include "Watcher.h"

class mytopic : public topic{
public:
	mytopic(int d) :
		m_data(d){}

	virtual void insertwach(Watcher* w) override{
		m_watcher.push_back(w);
	}
	virtual void remvovewatch(Watcher* w) override{
		m_watcher.remove(w);
	}
	virtual void notify() override{
		for (auto i : m_watcher){
			i->dosomething(m_data);
		}
	}
	void setdata(int data){
		int temp = m_data;
		m_data = data;
		if (temp != m_data){
			notify();
		}
	}
private:
	int m_data;
};

当主题数据产生变化时,通知Watcher更新。

5、main函数

#include "mytop.h"
#include "Watcher1.h"
#include "Watcher2.h"

void main(){
	Watcher* myw1 = new Watcher1();
	Watcher* myw2 = new Watcher2();
	topic* myt = new mytopic(0);
	myt->insertwach(myw1);
	myt->insertwach(myw2);
	for (int i = 0; i < 10; ++i){
		dynamic_cast<mytopic*>(myt)->setdata(i);   //指向基类指针需要强转调用派生类定义的方法
	}
	return;
}

6、运行结果
在这里插入图片描述
可以看到,传入的int数据,两个观察者用不同的方法在控制台显示。

后记

1、使用面向对象的抽象,观察者模式使得我们可以独立地改变主题和观察者,使两者的依赖关系达到松耦合;
2、主题发送通知时,无需指定观察者,通知会自动传播;
3、观察者自己决定是否需要订阅通知,主题对象对此一无所知;
4、观察者模式是基于事件的UI框架中常用设计模式,也是MVC模式的一个重要组成部分。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值