设计模式之观察者模式(C++)

观察者模式(Observer):定义了对象间的一种一对多的关系,当一个对象改变时,所有依赖他的对象都得到通知并自动更新。

动机:

将一个系统划分成一系列相互协作的类有一个常用的副作用:需要维护相关对象间的一致性,我们不希望为了维护一致而是的各类紧密耦合,因为主要降低了系统的可复用性,因此利用观察者模式可以描述建立一种各层次之间的关系的模型,当被依赖的某个对象的状态发生变更时,所有依赖的对象的状态都得到更新。当前很多大型代码结构中都用到了一种事件机制,这种事件机制其实就是观察者模式的一种,订阅者订阅目标的某个时期,当目标触发该事件时通知订阅者。如Windows开发中我们订阅系统的鼠标单击事件,当我们鼠标单击我们程序的窗口时,操作系统就会发布鼠标单击系统给相应的订阅者,订阅者执行相应的操作。


适用性:

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

2、当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。

3、当一个对象必须通知其他对象,而它又不能假定其他对象时谁。换言之,你不希望对象之间是紧密耦合的。


通用观察者模式UML类图

Subject(目标):抽象的目标类,提供了一个抽象的Notify,和增加/删除对象引用的的接口。

ConcreteSubject:具体目标类,实现了抽象目标类的接口,同时增加了设置对象状态属性和获取状态属性的方法。

注意的是:目标类维护了一个观察者的对象列表,需要订阅Subject对象状态改变的类都必须向具体的目标对象注册自己,当具体目标类对象状态改变时,根据维护的观察者对象列表来通知观察者对象改变。


Obserber(观察者/订阅者):观察者抽象类,提供了一个更新状态的抽象接口。

ConcterteObserver1/ConcreteObserver2:具体观察者类,实现抽象类的接口,并增加了一个显示当前状态的函数。


实例代码如下:

Observer.h

#ifndef Observer_h_
#define Observer_h_

#include <iostream>
#include <list>
class Observer;

const int NET_STAT_UNCONNET = 0;
const int NET_STAT_LISTENING = 1;
const int NET_STAT_CONNCTED = 2;

class Subject
{
public:
	virtual ~Subject(){};
	virtual bool Attach(Observer*)=0;
	virtual bool Detach(Observer*)=0;
	virtual void Notify() = 0;
	void SetState(int state){ this->m_state = state; }
	int GetState(){ return m_state; }
protected:
	int m_state;

};


class ConcreteSubject :public Subject
{
public:
	ConcreteSubject();
	virtual ~ConcreteSubject(){};
	void Notify();
	virtual bool Attach(Observer*);
	virtual bool Detach(Observer*);
private:
	std::list<Observer*> m_observer_List;
};

class Observer
{
public:
	virtual ~Observer(){};
	virtual void Update(Subject*)=0;
	void ShowState(){ std::cout << "state: " << m_state << std::endl; }
protected:
	int m_state;
};

class ConcrtrObserver1:public Observer
{
public:
	virtual void Update(Subject*);
	ConcrtrObserver1();
	virtual ~ConcrtrObserver1(){};
};

class ConcrtrObserver2 :public Observer
{
public:
	virtual void Update(Subject*);
	ConcrtrObserver2();
	virtual ~ConcrtrObserver2(){};
};
#endif

Observer.cpp

#include "Observer.h"
#include <algorithm>


ConcreteSubject::ConcreteSubject()
{
	m_state = NET_STAT_UNCONNET;
}

bool ConcreteSubject::Attach(Observer* pObser)
{
	m_observer_List.push_back(pObser);
	std::cout << "Insert an Observer\n";
	return true;
}

bool ConcreteSubject::Detach(Observer* pObser)
{
	std::list<Observer*>::iterator it;
	for (it = m_observer_List.begin(); it != m_observer_List.end(); it++)
	{
		if (*it == pObser)
		{
			m_observer_List.erase(it);
			std::cout << "Erase an observer\n";
			break;
		}
	}
	return true;
}

void ConcreteSubject::Notify()
{
	std::list<Observer*>::iterator it;
	for (it = m_observer_List.begin(); it != m_observer_List.end(); it++)
	{
	
		(*it)->Update(this);
	}
}

ConcrtrObserver1::ConcrtrObserver1()
{
	m_state = NET_STAT_UNCONNET;
}

void ConcrtrObserver1::Update(Subject* pSubject)
{
	this->m_state = pSubject->GetState();
	ShowState();
}

ConcrtrObserver2::ConcrtrObserver2()
{
	m_state = NET_STAT_UNCONNET;
}

void ConcrtrObserver2::Update(Subject* pSubject)
{
	this->m_state = pSubject->GetState();
	ShowState();
}

客户端代码:

#include"Observer.h"

int main()
{
	ConcrtrObserver1 *pObser1 = new ConcrtrObserver1();
	ConcrtrObserver2 *pObser2 = new ConcrtrObserver2();
	ConcrtrObserver1 *pObser3 = new ConcrtrObserver1();
	ConcrtrObserver2 *pObser4 = new ConcrtrObserver2();
	ConcreteSubject *pSubject = new ConcreteSubject();
	pSubject->Attach(pObser1);
	pSubject->Attach(pObser2);
	pSubject->Attach(pObser3);
	pSubject->Attach(pObser4);
	
	pSubject->SetState(NET_STAT_LISTENING);
	pSubject->Notify();

	pSubject->Detach(pObser3);
	pSubject->SetState(NET_STAT_CONNCTED);
	pSubject->Notify();

	delete pObser1;
	delete pObser2;
	delete pObser3;
	delete pObser4;
	delete pSubject;
	return 0;
}


实例代码运行结果:



观察者模式的最重要目标是接触耦合,让耦合的双发都依赖于抽象,而不应该依赖于具体,从而使得各自的变化不会影响到另一边的变化。(依赖倒换原则)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值