设计模式学习笔记--观察者模式

本文详细探讨了观察者模式,从简介到实现细节,再到适用场景和与回调函数的对比,全面解析这一经典的设计模式在编程和架构设计中的应用。
摘要由CSDN通过智能技术生成

一.简介

观察者模式是一种灰常灰常重要的设计模式!在我们编程的时候经常会用到观察者模式,虽然我们自己可能并不知道。观察者模式又叫做发布-订阅模式。定义了一种一对多的依赖关系,让多个观察者同时监听同一个对象,该对象的状态发生改变时,会通知所有观察者对象,使他们更新自己。
举个例子来说,比如我们在玩一个网络游戏,场景中出现了一个BOSS,那么所有在这个场景中的人都应该能知道BOSS出现了,换句话说,服务器端需要将BOSS出现的这个信息发给所有在这个地图上的玩家。而要实现通知,服务器肯定不会去遍历所有在服务器中的玩家找出在此场景的玩家,这样做太耗费时间了,更好的做法是玩家进入了这个场景,就将自己“注册”到这个场景的一个列表中。这样当有消息需要发布时,服务器只需要遍历这个列表,就可以通知所有在这个地图上的玩家了。

观察者模式的UML图如下:

二.观察者模式的实现

关于观察者模式的实现,看下面的一个例子:
// C++Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <list>
using namespace std;


//抽象观察者类
class Observer
{
public:
	virtual void Update() = 0; 
};

//抽象主题类,被观察的对象
class Subject
{
private:
	//观察者列表
	typedef list<Observer*> ObserverList;
	ObserverList m_ObserverList;
public:
	//添加观察者
	void AddObserver(Observer* observer);
	//删除观察者
	void DelObserver(Observer* observer);

	//通知观察者进行更新
	void Notify();
};

void Subject::AddObserver(Observer* observer)
{
	m_ObserverList.push_back(observer);
}

void Subject::DelObserver(Observer* observer)
{
	m_ObserverList.remove(observer);
}

void Subject::Notify()
{
	for(ObserverList::iterator it = m_ObserverList.begin();it != m_ObserverList.end(); ++it)
	{
		(*it)->Update();
	}
}

//具体观察者类
class ConcreteObserver : public Observer
{
private:
	string m_name;
public:
	void SetName(string name);
	void Update() override;
};

void ConcreteObserver::SetName(string name)
{
	m_name = name;
}

void ConcreteObserver::Update()
{
	cout<<"Concrete Observer "<<m_name<<" update"<<endl;
}

//具体主题类,被观察者
class ConcreteSubject : public Subject
{
	//此处未给出具体实现
};

int _tmain(int argc, _TCHAR* argv[])
{
	//创建具体主题类(被观察者)
	ConcreteSubject* subject = new ConcreteSubject();
	//创建观察者
	ConcreteObserver* observer1 = new ConcreteObserver();
	observer1->SetName("Observer1");
	ConcreteObserver* observer2 = new ConcreteObserver();
	observer2->SetName("Observer2");
	ConcreteObserver* observer3 = new ConcreteObserver();
	observer3->SetName("Observer3");

	//将观察者注册到主题对象中
	subject->AddObserver(observer1);
	subject->AddObserver(observer2);
	subject->AddObserver(observer3);

	//主题对象有操作了,通知具体对象
	subject->Notify();


	//取消观察者3号的注册
	cout<<endl;
	subject->DelObserver(observer3);
	subject->Notify();

	system("pause");
	return 0;
}
结果:
Concrete Observer Observer1 update
Concrete Observer Observer2 update
Concrete Observer Observer3 update


Concrete Observer Observer1 update
Concrete Observer Observer2 update
请按任意键继续. . .


例子中,我们将Observer注册到了Subject中了,这样,如果Subject有任何变化,都可以通过调用Notify方法,通过Subject来多态调用各个ConcreteObserver的Update方法。当然这个注册也是提供注销操作的,我们将Observer3注销之后,再次Notify之后,他就没有再收到消息了。


三.观察者模式的使用条件

虽然这个是被观察对象改变之后,通知所有观察对象,但是可以继续引申一下,比如给观察者提供一个接口,让其可以通过被观察者的接口进行通知,或者直接将被观察者置为单例模式,这样就可以在一群对象中,一个对象的状态改变,通知所有对象。
观察者模式非常非常常用,在很多情况下我们都会用到它。著名的MVC架构就是基于观察者模式的。它为实现对象之间的联动提供了一整套解决方案,涉及到一对一或者一对多的对象交互时就可以考虑使用观察者模式。

观察者模式有如下优点:
1.可以在目标和观察者之间建立抽象的耦合,观察目标不需要了解观察者内部构造,只需要了解一个通知观察者的接口即可。
2.观察者模式可以实现表示和数据逻辑的分离,定义了稳定的消息传递机制,抽象了接口,让不同的表示层充当具体的观察者角色,观察者只需要继承抽象接口即可。、
3.观察者模式支持广播通信,可以向多个目标发送消息。
4.新增观察者无需修改原有系统代码,符合“开放封闭原则”。

但是观察者模式也有一些缺点:
1.虽然比暴力查询模式效率高得多,但是如果观察者较多的话,传递消息也是比较慢
2.如果观察者和目标之间存在循环依赖,观察者会触发他们之间的循环调用,可能导致崩溃。
3.没有让观察者知道目标怎么发生变化,只能知道目标发生了变化。


四.观察者模式和回调函数

关于观察这模式与回调函数是什么关系呢?个人感觉回调函数是一种观察者模式的实现方式,如果在没有对象概念的C中,要实现观察者模式一般就要用回调函数来实现。函数回调的过程其实就是一个“发布-订阅”的过程。我们将函数赋给函数指针,就是注册的过程,当状态改变就可以通过函数指针来进行回调,让观察者行动。而在面向对象语言中,我们就可以用面向对象的思维来更进一步实现观察者模式。我们注册的内容不再仅仅是一个函数指针,而变成了一个对象的指针或者引用,这样比单用函数指针可以实现的操作更多。
PS:关于函数指针,以及回调函数,可以参考: http://blog.csdn.net/puppet_master/article/details/49368863


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值