观察者模式Observer Pattern

UML类图

Observer(观察者基类)

  • 为那些在目标发生改变时需获得通知的对象定义一个更新接口

Subject(观察目标基类,可以理解为通知者)

  • 目标知道它的观察者(它被那些观察者观察)。可以有任意多个观察者观察同一个目标;

  • 提供注册和注销观察者对象的接口。

ConcreteObserver(具体的观察者)

  • 维护一个指向ConcreteSubject对象的引用;

  • 存储有关状态,这些状态应与目标的状态保持一致;

  • 实现Observer的更新接口以使自身状态与目标的状态保持一致。

ConcreteSubject(具体的被观察者即观察目标)

  • 将有关状态存入各ConcreteObserver对象;

  • 当它的状态发生改变时,向它的各个观察者发出通知

一、定义:观察者模式又被称为:发布订阅模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。可以理解为一个对象行为的改变,其相关联的对象都会得到通知,并自动产生对应的行为。

二、适用场景:在以下任一情况下都可以使用观察者模式:

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;

  • 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;

  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。

  • 凡是涉及到消息更新、广播机制、消息传递、链式触发都可以考虑使用观察者模式

三、“观察”不是“直接调用”

实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。不管是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。

四、实现形式:

实现观察者模式有非常多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式。

观察者模式按照以下方式进行协作:

  • 当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者;

  • 在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致

五、应用实例:

  • 拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。

  • 西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。

  • 对同一组数据进行统计分析时候, 我们希望能够提供多种形式的表示 (例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据, 我们当然需要当数据改变的时候, 所有的统计的显示都能够同时改变。

六、实例代码

点击查看代码
/*
*一般情况下,观察目标只有一个,即一对多的关系
*/
// observer.h
#include <list>

//通知的消息类型
enum class NotifyType
{
	Eat = 0,
	Drink,
	Play,
	Work,
};

class Observer;

//通知者(观察目标)
class Subject
{
protected:
	std::list<Observer*> m_observers;
public:
	void attach(Observer*);   //注册(添加一个观察者)
	void detach(Observer*);   //注销(删除一个观察者)
	virtual void notify() = 0; //通知
};

//观察者
class Observer
{
public:
	virtual void update(NotifyType type) = 0;  //更新
	virtual ~Observer() {};
};

//具体的观察者:员工A
class WorkerA :public Observer
{
	void update(NotifyType type) override;
};

//具体的观察者:员工B
class WorkerB :public Observer
{
	void update(NotifyType type) override;
};

//具体的观察者:员工C
class WorkerC :public Observer
{
	void update(NotifyType type) override;
};

//具体的通知者:组长
class Leader :public Subject
{
public:
	void notify() override;
};

//具体的通知者:经理
class Manager :public Subject
{
public:
	void notify() override;
};

//具体的通知者:老板
class Boss :public Subject
{
public:
	void notify() override;
};

// observer.cpp
#include "observer.h"
#include <iostream>

void Subject::attach(Observer* obs)
{
	m_observers.emplace_back(obs);
}

void Subject::detach(Observer* obs)
{
	auto it = m_observers.begin();
	while (it != m_observers.end())
	{
		if (*it == obs)
			m_observers.erase(it);
		it++;
	}
}

void Leader::notify()
{
	//组长通知一起去洗脚
	std::cout << "\t组长发通知了\n";
	for (const auto& elem : m_observers)
	{
		elem->update(NotifyType::Play);
	} 
}

void Manager::notify()
{
	//经理通知今晚加班
	std::cout << "\t经理发通知了\n";
	for (const auto& elem : m_observers)
	{
		elem->update(NotifyType::Work);
	}
}

void Boss::notify()
{
	//老板通知今晚一起吃饭喝酒
	std::cout << "\t老板发通知了\n";
	for (const auto& elem : m_observers)
	{
		elem->update(NotifyType::Eat);
		elem->update(NotifyType::Drink);
	}
}

void WorkerA::update(NotifyType type)
{
	switch (type)
	{
	case NotifyType::Eat:
		std::cout << "WorkerA:\t去吃饭咯。\n";
		break;
	case NotifyType::Drink:
		std::cout << "WorkerA:\t去喝酒咯。\n";
		break;
	case NotifyType::Play:
		std::cout << "WorkerA:\t去洗脚咯。\n";
		break;
	case NotifyType::Work:
		std::cout << "WorkerA:\t装作认真工作的样子。\n";
		break;
	default:
		break;
	}
}

void WorkerB::update(NotifyType type)
{
	switch (type)
	{
	case NotifyType::Eat:
		std::cout << "WorkerB:\t我不去吃饭。\n";
		break;
	case NotifyType::Drink:
		std::cout << "WorkerB:\t我不去喝酒。\n";
		break;
	case NotifyType::Play:
		std::cout << "WorkerB:\t一起去洗脚咯。\n";
		break;
	case NotifyType::Work:
		std::cout << "WorkerB:\t加你麻痹班!\n";
		break;
	default:
		break;
	}
}

void WorkerC::update(NotifyType type)
{
	switch (type)
	{
	case NotifyType::Eat:
		std::cout << "WorkerC:\t我先回家了。\n";
		break;
	case NotifyType::Drink:
		std::cout << "WorkerC:\t我不会喝酒。\n";
		break;
	case NotifyType::Play:
		std::cout << "WorkerC:\t这次去哪洗脚?\n";
		break;
	case NotifyType::Work:
		std::cout << "WorkerC:\t我要带孩子先溜了,你们好好加班。\n";
		break;
	default:
		break;
	}
}
// main.cpp
#include "observer.h"

int main()
{   
    //观察目标对象
    Subject* leader = new Leader();
    Subject* manager = new Manager();
    Subject* boss = new Boss();

    //观察者对象
    Observer* workerA = new WorkerA();
    Observer* workerB = new WorkerB();
    Observer* workerC = new WorkerC();

    //给观察目标添加观察者
    leader->attach(workerA);
    leader->attach(workerB);
    leader->attach(workerC);

    manager->attach(workerA);
    manager->attach(workerB);
    manager->attach(workerC);

    boss->attach(workerA);
    boss->attach(workerB);
    boss->attach(workerC);

    //观察目标状态改变发出通知
    leader->notify();
    manager->notify();
    boss->notify();

    return 0;
}

参考:
设计模式之观察者模式(c++)

观察者模式的程序实例C++

posted @ 2021-06-01 19:31  滴哒哒哒  阅读(52)  评论(0编辑  收藏  举报