设计模式 - 观察者模式

观察者模式,也有叫发布-订阅模式的。这是个人比较喜欢的设计模式之一。因为它比较容易使用,而且效果还挺好。

意图

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

结构

其实,观察者模式里面目标对象和观察者对象还是松耦合的。目标对象需要知道观察者的一些比较固定的接口,比如Update(),同时观察者也需要知道目标对象的一些状态,因为观察者需要根据目标对象的状态信息来更新。

IM通讯软件里面,比如qq,当你的好友发一条信息给你的时候,屏幕右下角的qq图标会不停的跳动。在这个例子里面,qq肯定会有一个接收网络数据的对象,这就是个目标对象,同时右下角的图标是个系统托盘对象,也可以理解为观察者对象。当然我并不知道qq是否这么做的,但是我感觉是可以使用观察者模式的。当网络对象接收到一条信息的时候,就可以更新右下角的系统托盘对象,将图标动起来。

这里整一个比较简单的例子,假设我们写了一个通讯软件的客户端。每当收到一条信息的时候,就需要将这条信息显示到对话框上。

先定义目标对象基类

class CSubject
{
public:
	virtual const string& GetMsg() = 0;
	virtual void Attach(CObserver* observer) = 0;
	virtual void Notify() = 0;
};

注意其中的Attach函数,这个函数就是将一个观察者对象保存到目标对象里面。这样目标对象就可以更新观察者对象。

 

再定义一个观察者对象基类

class CObserver
{
public:
	virtual void Update(CSubject* subject) = 0;
};

只有一个函数Update(),这个函数将被目标对象调用。

再看看各自的子类:

首先是网络接收对象

class CReceiver: public CSubject
{
public:
	const string& GetMsg(){return m_msg;}

	//实现增加观察者函数
	void Attach(CObserver* observer)
	{
		m_listObservers.push_back(observer);
	}

	//通知所有的观察者更新数据
	void Notify()
	{
		BOOST_FOREACH(CObserver* observer, m_listObservers)
		{
			observer->Update(this);
		}
	}

	//模拟接收到一条信息
	void ReceivedMsg(const string& msg)
	{
		m_msg = msg;
		Notify();//更新观察者。
	}
protected:
	list<CObserver*> m_listObservers; 
	string m_msg;
};

每当收到一条信息的时候,就调用Notify函数来更新所有的观察者。

观察者的实现:

class CMsgDialog: public CObserver
{
public:
	virtual void Update(CSubject* subject)
	{
		cout << "show msg: " << subject->GetMsg() << "\n";
	}
};

将目标对象的内容显示出来。

简单调用例子

void Pattern_Observer()
{
	//模拟生成一个接收数据对象,这是一个目标对象
	CReceiver* receiver = new CReceiver();

	CMsgDialog* dlg = new CMsgDialog();

	//将观察者attach到目标对象
	receiver->Attach(dlg);

	//模拟接收对象收到一条信息
	receiver->ReceivedMsg("dinner together\n");
}

当接收对象收到一条信息的时候(这里是模拟的)receiver->ReceivedMsg("dinner together\n");

观察者对象将会自动被更新。

 

这个就是一个最最简单的观察者模式例子。其实这里会有个问题,目标对象将所有的观察者对象都更新了一下。这个就是所谓的推模型。目标对象不管观察者是否需要更新,都直接更新它们。那么假如有些观察者不需要更新呢?就可以考虑拉模型。拉模型就是由观察者主动通知目标对象,然后目标对象再更新观察者(观察者怎么知道什么时候可以更新了呢?这是一个问题)。

 

个人感觉观察者模式还是蛮有用的,效果还是可以的。但是这里有个问题,就是目标对象和观察者之间有一定程度的耦合。尽管我们可以降低耦合程度,但是毕竟还是避免不了耦合。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值