观察者模式

观察者模式:定义对象与对象之间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并更新。

 

    大家在高中时,每到自习课时都异常活跃:玩手机、聊天、打牌。。。。。然而每每到最活跃的时候,班主任老师就来了,然后收手机、收扑克牌、还要训斥一顿。

    为了能让同学有好的自习体验,今天张三同学站了出来,主动帮我们盯梢,如果老师来了就私发条消息给其他同学。其他同学要做的只需要在张三那里报个名,好让张三能通知到自己。

   那么这一情形就是个典型的"观察者模型":

观察者结构图

 

    作为通知者:张三,他的状态关乎其他人的状态。如果老师来了,张三需要通知给登记过的同学,哪些同学也就能及时收起手机、扑克进入到学习状态。

    所以通知者需要能:增加、删除观察者对象,通知观察者改变状态,改变通知者自己的状态。

class Observer;

/* 通知者接口 */
class Subject{
public:
    // 添加被通知者
    virtual void Attach(Observer* obs) {}	
	   
    // 移除被通知者
	virtual void Detach(Observer* obs) {}
	
    // 通知登记的同学
	virtual void Notify() {}
	
    // 设置通知者状态接口
	void SetState(string s){
		action = s;
	}
	
    // 获取通知者状态接口
	string GetState(){ 
		return action; 
	}

private:
	string action;

};

  作为其他同学(观察者),需要在收到通知者的通知时更新自己的状态。 

/* 观察者接口 */
class Observer{
public:
	Observer(string name, Subject* sub)
		:_name(name)
		, _sub(sub)
	{}

	// 更新到学习状态
	virtual void Update(){}


public:
	string _name;
	Subject* _sub;

};

 

/* 哨兵类 */
class Sentry : public Subject{
public:

	void Attach(Observer* obs){
		obs_list.push_back(obs);
	}

	void Detach(Observer* obs){
		obs_list.remove(obs);
	}

	void Nofity();

private:
    // 登记需要被通知的同学
	list<Observer*> obs_list;
};


/* 玩手机的同学类 */
class MobilePhone :public Observer{
public:
	MobilePhone(string name, Subject* sub)
		:Observer(name, sub)
	{}

	void Update(){
		cout << _sub->GetState() << _name << "收起手机,开始学习!!!" << endl;
	}
};


void Sentry::Nofity(){
	list<Observer*>::iterator it;
	for (it = obs_list.begin(); it != obs_list.end(); it++)
		(*it)->Update();
}

    如果张三在盯梢的时候,打了个盹,那么通知各位同学的就是老师了,所以我们容易理解,在实现上观察者不能依赖某一具体类,而应该是一个抽象的通知者。所以我们提供的是一个通知者接口,而之后具体实现上可以是哨兵张三,也可以是老师、甚至校长,他们也可以有自己的方法,但作为通知者他们是一样的(通知学生,进入学习状态)。

    同样作为观察者,也可能由不同的状态改变:玩手机 -> 学习;聊天 -> 学习; 打牌 -> 学习...。所以通知者在通知时,也应该是通知一个抽象的观察者。

  客端调用:

int main()
{
	// 哨兵张三
	Sentry* zhangsan = new Sentry();

	// 玩手机的同学
	MobilePhone* mp1 = new MobilePhone("李四", zhangsan);
	MobilePhone* mp2 = new MobilePhone("王五", zhangsan);
	MobilePhone* mp3 = new MobilePhone("赵六", zhangsan);

	zhangsan->Attach(mp1);
	zhangsan->Attach(mp2);
	zhangsan->Attach(mp3);

	zhangsan->SetState("张三:老师来了!!!   ");

	zhangsan->Nofity();

	return 0;
}

  玩手机的同学就能收到,张三的通知了: 

 

特点:

将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性,我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用带来不便。而观察者模式关键对象是主题Subject和观察者Observer,一个Subject 可以有任意数量的依赖它的 Observer,一旦 Subject 发生变化,所有 Observer 都可以得到通知,Subject 发出通知时并不需要知道谁是它的观察者,任何一个具体的观察者也不需要知道其他观察者的存在。

***使用情况 GOF 给出了以下使用观察者模式的情况:

  1. 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  2. 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
  3. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望 这些对象是紧密耦合的。

 

本篇参照《大话设计模式》、《深入浅出设计模式》、《设计模式:可复用面向对象软件的基础》相关章节内容。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值