大话设计模式 —— 第十四章《观察者模式》C++ 代码实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34536551/article/details/89298211

目录

定义

结构

优点

缺点

适用场景



定义


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

  • 举个例子:观察者模式可以理解为, 在一个一对多的关系模式中, 例如一个微信公众号有多个关注用户,那么关注该微信公众号的微信用户就是观察者,微信公众号就是被观察者.
  • 一个微信公众号会有多个关注用户,这就是其中的一对多的关系.然后当一个对象的状态发生改变就是说当被观察者(微信公众号)有了改变,例如添加了新的内容.这时候所有关注该公众号的微信用户就希望能得到通知.

结构


观察者模式UML图
  • Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
  • ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  • Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
  • ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。具体观察者角色可以保存一个指向具体主题对象的引用。

下面是用C++ 代码 实现大话数据结构本章:

#include<iostream>
#include<list>
#include<algorithm>
#include<string>
using namespace std;


class Observer  // 抽象观察者,为所有的观察者定义更新接口 (Update),当收到 Subject 的通知时,Observer 需要同步更新信息。
{
public:
	virtual ~Observer() = default;
	virtual void Update() = 0;

};

class Subject // 抽象主题类,也是抽象被观察者
{
public:
	virtual ~Subject() = default;
	virtual void Attach(Observer* observer) = 0;
	virtual void Detach(Observer* observer) = 0;
	virtual void Notify() = 0; //通知所有观察者
};

class ConcreteSubject : public Subject  // 具体主题类,也是具体被观察者
{
private:
	string subjectState;
	list<Observer*> observers;
public:
	void Attach(Observer* observer)override  //添加观察者
	{
		observers.push_back(observer);
	}
	void Detach(Observer* observer)override // 删除观察者
	{
		while (!observers.empty())
		{
			for (auto it = observers.begin(); it != observers.end(); ++it)
			{
				if (*it == observer)
				{
					observers.erase(it);
					break;
				}
			}
			break;
		}
	}
	void Notify() override //通知所有观察者
	{
		while (!observers.empty())
		{
			for (auto item : observers)
			{
				item->Update(); // 更新当前具体主题对象的状态到所有观察者中
			}
			break;
		}
	}
	string GetSubjectState() //设置状态
	{
		return subjectState;
	}
	void SetSubjectState(string state) // 获得状态
	{
		subjectState = state;
	}
	
};

class ConcreterObserver : public Observer
{// 具体观察者
private:
	ConcreteSubject *m_subject;
	string m_name;
public:
	ConcreterObserver() = default;
	ConcreterObserver(ConcreteSubject *subject, string name) : m_subject(subject),m_name(name) {}

	void Update()override
	{
		// 具体主题对象状态发生改变时,观察者也发生改变。
		auto observerState = m_subject->GetSubjectState();
		cout << observerState << "," << m_name << "关闭股票行情,继续工作!" << endl;
	}
	
};
int main()
{
	ConcreteSubject *huhansan = new ConcreteSubject;

	ConcreterObserver *tongshi1 = new ConcreterObserver(huhansan, "魏关姹");
	ConcreterObserver *tongshi2 = new ConcreterObserver(huhansan, "易管察");
	ConcreterObserver *tongshi3 = new ConcreterObserver(huhansan, "霍华德");
	huhansan->Attach(tongshi1);
	huhansan->Attach(tongshi2);
	huhansan->Attach(tongshi3);

	//魏关姹没有被老板通知到,减去。
	huhansan->Detach(tongshi1);
	huhansan->SetSubjectState("我胡汉三回来了!");
	huhansan->Notify();

	delete huhansan;
	delete tongshi1;
	delete tongshi2;
	delete tongshi3;

	huhansan = nullptr;
	tongshi1 = tongshi2 = tongshi3 = nullptr;
	system("pause");
	return 0;
}

运行结果截图:

扫描二维码关注公众号,回复: 5986651 查看本文章

观察者模式主要的作用就是对象解耦,将观察者和被观察者完全隔离,只依赖于Subject和 Observer,使得原本对象处于松耦合,不会相互影响。


优点


观察者模式解除了具体主题和具体观察者的耦合

  • 由于主题接口仅仅依赖于观察者接口,因此具体主题只是知道它的观察者是实现观察者接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题接口,因此具体观察者只是知道它依赖的主题是实现主题接口的某个类的实例,但不需要知道具体是哪个类。

观察者和被观察者之间是抽象耦合的,容易扩展

  • 观察者模式满足“开-闭原则”。主题接口仅仅依赖于观察者接口,这样,就可以让创建具体主题的类也仅仅是依赖于观察者接口,因此,如果增加新的实现观察者接口的类,不必修改创建具体主题的类的代码。同样,创建具体观察者的类仅仅依赖于主题接口,如果增加新的实现主题接口的类,也不必修改创建具体观察者类的代码。

缺点


  • 抽象通知者依然依赖于抽象观察者, 并未完全解除耦合
  • 在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且消息的通知一般是顺序执行,那么一个观察者卡顿,后面的所有观察者都会停止。会影响整体的执行效率,在这种情况下,可以考虑使用异步( 指的是多线程)解决,同时也需要确保异步不会出现问题


适用场景


  • 当一个对象的数据更新时需要通知其他对象,但这个对象又不希望和被通知的那些对象形成紧耦合。
  • 当一个对象的数据更新时,这个对象需要让其他对象也各自更新自己的数据,但这个对象不知道具体有多少对象需要更新数据。
  • 关联行为场景。关联行为是可拆分的,而不是组合关系
  • 事件多级触发场景
  • 跨系统的消息交换场景,如消息队列的处理机制

总的来讲,观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化

猜你喜欢

转载自blog.csdn.net/qq_34536551/article/details/89298211