对象间的联动--观察者模式

随着交通信号灯的变化。汽车的行为也将随之变化,一盏交通信号灯能够指挥多辆汽车。

在软件系统中,有些对象之间也存在类似交通信号灯和汽车之间的关系。一个对象状态或者行为的变化将导致其他对象的状态或者行为也发生变化,它们之间将产生联动。为了更好的描写叙述对象之间存在的这样的一对多(包含一对一)的联动。观察者模式应运而生,它定义对象之间一对多的依赖关系。让一个对象的改变可以影响其他对象。

观察者模式概述


观察者模式用于建立一种对象之间的依赖关系,一个对象发生改变时将通知其他对象,其他对象将相应作出反应。

在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标能够相应多个观察者,并且这些观察者之间没有不论什么相互联系。能够依据须要添加或者删除观察者,使得系统更易于扩展。


观察者模式定义


定义对象之间的一种一对多的依赖关系。使得每当一个对象状态发生改变时,其相关依赖对象皆能得到通知并被自己主动更新。观察者模式的别名包含“公布--订阅”模式。


观察者模式结构图




观察者模式结构图中包括下面4个角色:

(1) 抽象主题角色:把全部对观察者对象的引用保存在一个集合(std::list)中。每一个抽象主题角色都能够有随意数量的观察者。

抽象主题提供一个接口。能够添加和删除观察者角色。

一般用一个抽象类和接口来实现。

(2) 详细主题角色:在详细主题内部状态改变时,给全部登记过的观察者发出通知。详细主题角色通经常使用一个子类实现。


(3) 抽象观察者角色:为全部详细的观察者定义一个接口,在得到主题的通知时更新自己。
(4) 详细观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通经常使用一个子类实现。假设须要,详细观察者角色能够保存一个指向详细主题角色的引用。

观察者模式定义了一种一对多的依赖关系。让多个观察者对象同一时候监听某一个主题对象。这个主题对象在状态上发生变化时,会通知全部观察者对象。让它们可以自己主动更新自己。

JDK对观察者模式的支持

观察者模式在java语言中的地位很重要。在JDK的java.util包中。提供了Obsevable类(观察目标)以及Observer(观察者)接口,它们构成了JDK对观察者模式的支持。
例如以下图所看到的:

观察者模式与Java事件处理




Java GUI经典演示样例


观察者模式与MVC




观察者模式总结

主要长处

(1) 观察者模式能够实现表示层和数据逻辑层的分离。

(2) 观察者模式在观察目标和观察者之间建立了一个抽象的耦合。
(3) 观察者模式支持广播通信,观察目标向全部已注冊的观察者对象发送通知。简化一对多系统设计的难度。

主要缺点

(1) 观察者模式没有对应的机制让观察者知道所观察的目标对象是如何发生变化的,而不过知道观察目标发生了变化。

适用场景

(1) 一个抽象模型有两个方面。当中一个方面依赖还有一个方面。

(2) 一个对象的改变将导致一个或多个其他对象发生改变,而不知道详细有多少个对象发生改变。

观察者模式应用

简而言之,观察者模式=公布者+注冊者。


观察者模式用来对GUI中的动作做侦听。Swing GUI的样例就表明了动作侦听是如何实现观察者模式的。
以下是一个猎头的典型样例。这个图中有2个角色-猎头和求职者。求职者先在猎头处注冊,当有新的工作机会时猎头就会通知求职者。


演示样例代码例如以下:

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

class Subject;
//Observer接口:抽象观察者
class Observer{
private:
	string name;
public:
	Observer(string n):name(n){
	}
	string getName(){
		return name;
	}
	virtual void update(Subject* s)=0;
};

//Subject接口:抽象主题
class Observer;
class Subject{
protected:
	//定义一个观察者集合用于存储全部观察者对象
	list<Observer*> observerList;
public:
	//注冊方法,用于向观察者集合添加一个观察者
	virtual void registerObserver(Observer* observer){
		cout<<observer->getName()<<"向猎头注冊"<<endl;
		observerList.push_back(observer);
	};
	//注销方法。用于在观察者集合中删除一个观察者
	virtual void removeObserver(Observer* observer){
		list<Observer*>::iterator iter=find(observerList.begin(),observerList.end(),observer);
		if(iter==observerList.end()){
			cout<<observer->getName()<<"没有向猎头注冊"<<endl;
		}else{
			cout<<(*iter)->getName()<<"取消向猎头注冊"<<endl;
			observerList.erase(iter);
		}
		return;	
	}
	//声明抽象通知方法
	virtual void notifyAllObserver()=0;
};



//Hunter类:详细主题
class Hunter : public Subject{
private:
	list<string> jobs;
public:
	Hunter(){}

	//实现通知方法
	void notifyAllObserver(){
		list<Observer*>::iterator iter=observerList.begin();
		//遍历观察者集合,调用每个观察者的响应方法
		while(iter!=observerList.end()){
			(*iter)->update(this);
			++iter;
		}
	}

	//加入工作
	void addJob(string jobName){
		jobs.push_back(jobName);
		//观察目标发生变化,通知全部观察者
		notifyAllObserver();
	}

	//得到工作列表
	void getJobs(){
		list<string>::const_iterator iter=jobs.begin();
		cout<<"可提供的工作最新列表:"<<endl;
		while(iter!=jobs.end()){
			cout<<*iter<<endl;
			++iter;
		}
	}
};

//JobSeeker:详细观察者
class JobSeeker : public Observer{
public:
	JobSeeker(string name):Observer(name){
	}
	void update(Subject *s){
		cout<<getName()<<"得到猎头通知!"<<endl;	
		((Hunter*)s)->getJobs();//此处没有针对抽象编程
	}
};

//client測试代码
int main(){
	Hunter *hunter=new Hunter();
	Observer *observer1,*observer2;
	observer1=new JobSeeker("Mike");
	observer2=new JobSeeker("Jeff");
	hunter->registerObserver(observer1);
	hunter->registerObserver(observer2);
	hunter->addJob("Google Job");
	hunter->addJob("Yahoo Job");
	hunter->removeObserver(observer1);
	return 0;
}

程序执行结果:


posted @ 2017-05-09 08:01  lytwajue  阅读(299)  评论(0编辑  收藏  举报