观察者模式

观察者模式理解

观察者模式是一种行为设计模式,也叫发布订阅模式。它定义了一种一对多的依赖关系,让多个观察者同时监听一个主题对象,当主题对象状态发生变化,会自动通知所有的观察者更新状态。
可以理解为班长为其他学生放哨,当得知班主任要来教室的时候,通知其他同学,其他同学立即进入学习状态;也可以理解为发布订阅的形式,当发布者发布主题后,订阅了这个主题的所有订阅者便可以收到该消息。
下面是观察者模式下的两个示例。

观察者模式的示例1

开发环境:vs2017下控制台程序

代码

其中放哨的同学被定义为被观察者,即Observed,其他同学被定义为观察者,即Observer。此项目中只有一个ObserverPattern.cpp文件。
ObserverPattern.cpp

// ObserverPattern.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

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

/*
观察者模式
	一个被观察者,多个观察者(一对多的关系)观察者的动作取决与被观察者,也就是被观察者添加所有观察者后,
	观察的事情发生变化会通知所有的观察者,所有观察者做出响应
*/

class Observed;
//观察者
class Observer
{
public:
	Observer(Observed *observer = nullptr)
	{
		m_observer = observer;
	}
	~Observer()
	{
		//if (m_observer)//谁开辟谁释放的原则
		//{
		//	delete m_observer;
		//	m_observer = nullptr;
		//}
	}

	void update(const string & action)
	{
		cout << "action:" << action << endl;
		cout << "反应动作" << endl;
	}
private:
	Observed *m_observer;
};



//被观察者
class Observed
{
public:
	Observed()
	{
		m_observerList.clear();
	}
	~Observed()
	{
		//list<Observer*>::iterator it = m_observerList.begin();//delete的时候已经被释放,不需要再释放
		//for (; it != m_observerList.end(); ++it)
		//{
		//	if (*it)
		//	{
		//		delete *it;
		//		*it = nullptr;
		//	}
		//}
	}

	void notify(const string & notifyInfo) 
	{
		for (auto &var:m_observerList) 
		{
			var->update(notifyInfo);
		}
	}
	void addObserver(Observer *obj)
	{
		m_observerList.push_back(obj);
	}

	void detachObserver(Observer *obj) 
	{
		for (auto & var:m_observerList)
		{
			if (obj == var)
			{
				m_observerList.remove(var);
				break;
			}
		}
	}
private:
	list<Observer*> m_observerList;
};

 
int main()
{
	Observed *oberser = new Observed;
	Observer *obj1 = new Observer(oberser);
	Observer *obj2 = new Observer(oberser);

	oberser->addObserver(obj1);
	oberser->addObserver(obj2);

	oberser->notify("敌人来了");

	delete oberser;
	oberser = nullptr;

	delete obj1;
	obj1 = nullptr;

	delete obj2;
	obj2 = nullptr;
    
	return 0;
}

注意点

以上代码中我注释掉的部分都为所犯错误点,这里做详细说明。

注释点一

在析构函数中注释掉以下代码。

		//if (m_observer)//谁开辟谁释放的原则
		//{
		//	delete m_observer;
		//	m_observer = nullptr;
		//}

上述的ObserverPattern.cpp如果放开析构函数中注释掉的代码,在运行的时候会出现奔溃,主要因为main函数中调用了delete oberser;oberser = nullptr;析构了 被观察者Observed,而Observed类的变量作为观察者Observer 类的成员变量m_observer,当执行delete obj1;obj1 = nullptr;时会调用Observer类的析构函数,此时如果不注释掉上述析构函数中的代码,会导致当执行delete oberser;oberser = nullptr;后已经释放了被观察者指向的内存,又会执行一遍释放被观察者指向的内存,也就是对一块已经释放的内存再次释放了,所以会崩溃。本着谁开辟谁释放,上述ObserverPattern.cpp中析构函数内的释放内存那块应该注释掉。

注释点二

在被观察者类Observed的析构函数中注释掉释放链表中的观察者对象指针的代码。

~Observed()
	{
		//list<Observer*>::iterator it = m_observerList.begin();//delete的时候已经被释放,不需要再释放
		//for (; it != m_observerList.end(); ++it)
		//{
		//	if (*it)
		//	{
		//		delete *it;
		//		*it = nullptr;
		//	}
		//}
	}

被观察者类Observed有一个成员变量list<Observer*> m_observerList,上述代码看似没有问题,但是与主函数main中的代码

Observer *obj1 = new Observer(oberser);
Observer *obj2 = new Observer(oberser);

一起来看,就显得上述析构函数中的释放观察者指针就没有必要了,本着谁开辟谁释放的原则,obj1,obj2采用main函数中delete的方式释放,被观察者类Observed的成员变量list<Observer*> m_observerList中的观察者指针就会被释放。所以Observed类的析构函数链表中的元素被释放应该被注释。

观察者模式的示例2

使用发布者与订阅者对象,抽象类为基类,派生类派生于抽象基类。发布者扮演放哨者的角色,订阅者扮演观察者的角色,也就是被通知的对象,下面为具体的代码。
该部分代码相比示例1要更上一个档次,首先使用了C++11中的智能指针,可以自动回收资源,另外采用抽象类做为基类,派生类继承后重写虚函数,并增加自己的行为与属性,封装性上也比示例1也更好。

// ObserverPattern2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

#include <iostream>
#include <memory>
#include <string>
#include <list>

using namespace std;

/*
观察者模式
	智能指针实现观察者模式
*/

class BaseObeserve 
{
public:
	virtual ~BaseObeserve() {};
	virtual void update(const string & info) = 0;
};

class BaseObserved 
{
public:
	virtual ~BaseObserved(){}
	virtual void attach(shared_ptr<BaseObeserve> obeserve) = 0;
	virtual void detach(shared_ptr<BaseObeserve> observe) = 0;
	virtual void notify(const string &info) = 0;
};

class publish :public BaseObserved
{
public:
	void attach(shared_ptr<BaseObeserve> obeserve) override
	{
		m_observerList.push_back(obeserve);
	}

	void detach(shared_ptr<BaseObeserve> observe)override 
	{
		m_observerList.remove(observe);
	}

	void notify(const string &info)override 
	{
		for (auto & observe:m_observerList)
		{
			cout << "notify:注意了" << endl;
			observe->update(info);
		}
	}

	void createMessage(const string &info) //相当于创建主题
	{
		m_info = info;
		notify(m_info);
	}
private:
	string m_info;
	list<shared_ptr<BaseObeserve>> m_observerList;
};

class  subscriber :public BaseObeserve
{
public:
	subscriber(shared_ptr<BaseObserved> observed) :
		m_observed(observed)
	{
		m_observed->attach(make_shared<subscriber>(*this));
		m_count = m_number;
	}

	void update(const string & info)override 
	{
		m_mesg = info;
		cout << "info= " << info << endl;
	}

	void removeFromList() 
	{
		m_observed.get()->detach(make_shared<subscriber>(*this));
	}
private:
	string m_mesg;
	static int m_number;
	int m_count;
	shared_ptr<BaseObserved> m_observed;
};
int subscriber::m_number = 2;

void fun() 
{
	shared_ptr<publish> pub = shared_ptr<publish>(new publish());
	shared_ptr<subscriber> sub1 = shared_ptr<subscriber>(new subscriber(pub));
	shared_ptr<subscriber> sub2 = shared_ptr<subscriber>(new subscriber(pub));

	pub.get()->createMessage("敌人来了");

	//释放m_observerList中指针指向的内存
	sub1.get()->removeFromList();
	sub2.get()->removeFromList();
}

int main()
{
	fun();

	return 0;
}

示例三

该示例比较简洁,有助于理解,看这一个示例就可以。

示例代码

下面直接上代码:

//观察者
class Observer 
{
public:
	virtual void update() = 0;
};

class ObserverA :public Observer //观察者A
{
public:
	void update() override
	{
		cout << "更新ObserverA!" << endl;
	}
};

class ObserverB :public Observer//观察者B
{
public:
	void update() override
	{
		cout << "更新ObserverB!" << endl;
	}
};

class Subject //主题(被观察者)
{
public:
	void registerObserver(Observer *observer)//注册观察者
	{
		if(!observer)
		{
			cout << "观察者为空,无法注册!" << endl;
		}
		m_observer.push_back(observer);
	}
	void removeObserver(Observer *pObserver) //移除观察者
	{
		for (auto it = m_observer.begin();it != m_observer.end();++it) 
		{
			if (*it == pObserver)
			{
				m_observer.erase(it);
				break;
			}
		}
	}
	void notifyObserver() //通知所有的观察者
	{
		for (auto &observer:m_observer) 
		{
			observer->update();//观察者更新状态
		}
	}

private:
	vector<Observer*> m_observer;
};

测试代码

这里省略头文件。

int main()
 {
	Subject subject;
	ObserverA observer1;
	ObserverB observer2;
	subject.registerObserver(&observer1);
	subject.registerObserver(&observer2);
	subject.notifyObserver();
	subject.removeObserver(&observer2);
	subject.notifyObserver();

	return 0;
}

运行结果

在这里插入图片描述

应用场景

观察者模式主要应用场景包括:

  1. 当对象之间存在一对多的关系时,且一个对象的改变会影响其他多个对象时,可以使用观察者模式。

  2. 当系统需要在不同层次上将一个对象分离成多个类时,使用观察者模式可以降低系统的耦合度,并提高系统的可扩展性与可维护性。

  3. 当系统的某个对象状态发生改变后,需要及时通知其他相关对象时,使用观察者模式可以提高系统的响应速度与实时性。

  4. 当需要在一个对象状态改变时,采取一些特定的操作时,使用观察者模式可以简化系统设计,让设计更加符合“开闭原则”。

  5. 当需要增加新的观察者对象或者删除现有的观察者对象时,使用观察者模式可以方便地进行扩展,无需修改现有代码。

总之,观察者模式的应用场景和其概念基本是相通的,还是重在理解。

注意点

观察者模式分为被观察者和观察者,被观察者就相当于放哨的人,观察者相当于观察者,被观察者通知观察者相应的事情,其他所有观察者响应通知。被观察者有一个notify函数,观察者有一个update函数来响应通知,同时需要将所有的观察者加入到被观察者的成员变量list中,这就需要增加观察者,和删除观察者函数。其观察者模式还需要仔细领悟。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肩上风骋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值