作者卡奴达摩
连接:http://blog.youkuaiyun.com/zhengzhb/article/details/7471978
定义:定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
类型:行为类模式
类图:
在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化。比如,我们要设计一个右键菜单的功能,只要在软件的有效区域内点击鼠标右键,就会弹出一个菜单;再比如,我们要设计一个自动部署的功能,就像eclipse开发时,只要修改了文件,eclipse就会自动将修改的文件部署到服务器中。这两个功能有一个相似的地方,那就是一个对象要时刻监听着另一个对象,只要它的状态一发生改变,自己随之要做出相应的行动。其实,能够实现这一点的方案很多,但是,无疑使用观察者模式是一个主流的选择。
观察者模式的结构
在最基础的观察者模式中,包括以下四个角色:
- 被观察者:从类图中可以看到,类中有一个用来存放观察者对象的Vector容器(之所以使用Vector而不使用List,是因为多线程操作时,Vector在是安全的,而List则是不安全的),这个Vector容器是被观察者类的核心,另外还有三个方法:attach方法是向这个容器中添加观察者对象;detach方法是从容器中移除观察者对象;notify方法是依次调用观察者对象的对应方法。这个角色可以是接口,也可以是抽象类或者具体的类,因为很多情况下会与其他的模式混用,所以使用抽象类的情况比较多。
- 观察者:观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生变化时,这个方法就会被触发调用。
- 具体的被观察者:使用这个角色是为了便于扩展,可以在此角色中定义具体的业务逻辑。
- 具体的观察者:观察者接口的具体实现,在这个角色中,将定义被观察者对象状态发生变化时所要处理的逻辑。
观察者模式代码实现
abstract class Subject {
private Vector<Observer> obs = new Vector<Observer>();
public void addObserver(Observer obs){
this.obs.add(obs);
}
public void delObserver(Observer obs){
this.obs.remove(obs);
}
protected void notifyObserver(){
for(Observer o: obs){
o.update();
}
}
public abstract void doSomething();
}
class ConcreteSubject extends Subject {
public void doSomething(){
System.out.println("被观察者事件反生");
this.notifyObserver();
}
}
interface Observer {
public void update();
}
class ConcreteObserver1 implements Observer {
public void update() {
System.out.println("观察者1收到信息,并进行处理。");
}
}
class ConcreteObserver2 implements Observer {
public void update() {
System.out.println("观察者2收到信息,并进行处理。");
}
}
public class Client {
public static void main(String[] args){
Subject sub = new ConcreteSubject();
sub.addObserver(new ConcreteObserver1()); //添加观察者1
sub.addObserver(new ConcreteObserver2()); //添加观察者2
sub.doSomething();
}
}
运行结果
被观察者事件反生
观察者1收到信息,并进行处理。
观察者2收到信息,并进行处理。
通过运行结果可以看到,我们只调用了Subject的方法,但同时两个观察者的相关方法都被同时调用了。仔细看一下代码,其实很简单,无非就是在Subject类中关联一下Observer类,并且在doSomething方法中遍历一下Observer的update方法就行了。
观察者模式的优点
观察者与被观察者之间是属于轻度的关联关系,并且是抽象耦合的,这样,对于两者来说都比较容易进行扩展。
观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理。但同时,这也算是观察者模式一个缺点,由于是链式触发,当观察者比较多的时候,性能问题是比较令人担忧的。并且,在链式结构中,比较容易出现循环引用的错误,造成系统假死。
总结
Java语言中,有一个接口Observer,以及它的实现类Observable,对观察者角色常进行了实现。我们可以在jdk的api文档具体查看这两个类的使用方法。
做过VC++、JavaScript DOM或者AWT开发的朋友都对它们的事件处理感到神奇,了解了观察者模式,就对事件处理机制的原理有了一定的了解了。如果要设计一个事件触发处理机制的功能,使用观察者模式是一个不错的选择,AWT中的事件处理DEM(委派事件模型Delegation Event Model)就是使用观察者模式实现的。
作者:RayChase
连接:http://raychase.iteye.com/blog/1337015
观察者模式,指的是定义一种对象间的一对多的关系,当一个对象的状态发生变化的时候,所有依赖于它的对象都将得到通知并更新自己。
现在要说的分歧在这里:
“推”的方式是指,Subject维护一份观察者的列表,每当有更新发生,Subject会把更新消息主动推送到各个Observer去。
“拉”的方式是指,各个Observer维护各自所关心的Subject列表,自行决定在合适的时间去Subject获取相应的更新数据。
“推”的好处包括:
1、高效。如果没有更新发生,不会有任何更新消息推送的动作,即每次消息推送都发生在确确实实的更新事件之后,都是有意义的。
2、实时。事件发生后的第一时间即可触发通知操作。
3、可以由Subject确立通知的时间,可以避开一些繁忙时间。
4、可以表达出不同事件发生的先后顺序。
“拉”的好处包括:
1、如果观察者众多,Subject来维护订阅者的列表,可能困难,或者臃肿,把订阅关系解脱到Observer去完成。
2、Observer可以不理会它不关心的变更事件,只需要去获取自己感兴趣的事件即可。
3、Observer可以自行决定获取更新事件的时间。
4、拉的形式可以让Subject更好地控制各个Observer每次查询更新的访问权限。
----------------------------------------------------------------------------------------------------------------------------------
2012-2-27 补充:
事实上“推”和“拉”可以比较的内容太多了,比如:
客户端通常是不稳定的,服务端是稳定的,如果消息由客户端主动发起去获取,它很容易找到服务端的地址,可以比较容易地做到权限控制(集中在服务端一处),服务端也可以比较容易地跟踪客户端的位置和状态,反之则不行;
互联网页面的访问就是一个最好的“拉”的模式的例子;
通常我们希望把压力分散到各个客户端上去,服务端只做最核心的事情,只提供内容,不管理分发列表;
……
还有一个idea是关于“推”和“拉”结合的形式,例如,服务端只负责通知某一些数据已经准备好,至于是否需要获取和什么时候客户端来获取这些数据,完全由客户端自行确定。
、、、、、、、转者、、、、、、、
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <algorithm>
/**********************************************************************************
最开始使用智能指针实现的,但是发现了一些"问题":
1、智能指针没有复制兼容性原则:指向子类的智能指针不能向指向父类的智能指针赋值/初始化
2、指向基类的智能指针甚至不能用来指向原生的子类对象
除非自己实现转换函数,且转换函数的频繁调用成为必然,但实际上不应该频繁的转换类型
一些注意事项,观察者在自身析构之前,必须向主题取消注册,以免产生不必要的麻烦
***********************************************************************************/
class AbsSubject; //前向声明
class AbsObserver
{
public:
virtual void Update(std::string report) = 0; //推送内容方式,注意 主题与观察者是分离的,不要盲目追求效率而声明参数为引用
virtual void Updata(AbsSubject *sj) = 0; //拉取内容方式,想要知道具体主题的具体内容,需自己去取感兴趣的项,此方式需求客户遵守约定,并且不在运行时修改成员变量
virtual ~AbsObserver(){};
};
class AbsSubject
{
public:
virtual void RegisterObserver(AbsObserver *ob) = 0; //由于允许子类自行选取数据结构存储观察者,因此定义为纯虚函数,此外,此处也助于减少行为的继承
virtual void CancelObserver(AbsObserver *ob) = 0;
virtual void Notify() = 0;
virtual ~AbsSubject(){}; //AbsSubject的子类中可能拥有指向观察者的指针,但不应该在析构函数中释放这些指针,毕竟主题与观察者是独立的
};
class Secretary : public AbsSubject //专用秘书,单人使用
{
private:
AbsObserver *pLeader;
std::string plan;
void Notify()
{
if( NULL != pLeader )
{
pLeader->Update(plan);
}
}
public:
Secretary() : pLeader(NULL)
{
}
explicit Secretary(AbsObserver *ob)
{
RegisterObserver(std::move(ob));
}
void RegisterObserver(AbsObserver *ob)
{
pLeader = ob;
}
void CancelObserver(AbsObserver *ob)
{
pLeader = NULL;
}
void SetPlan(std::string NewPlan)
{
plan = NewPlan;
Notify();
}
};
class Reception : public AbsSubject //勤劳的前台MM
{
private:
std::vector<AbsObserver *> member;
std::string bossEvent;
std::string managerEvent;
std::string HREvent;
public:
Reception()
{
}
explicit Reception(AbsObserver *ob)
{
RegisterObserver(ob);
}
void RegisterObserver(AbsObserver *ob)
{
member.push_back(std::move(ob)); //避免拷贝
}
void CancelObserver(AbsObserver *ob)
{
std::vector<AbsObserver *>::const_iterator it;
it = std::find(member.cbegin(), member.cend(), ob);
if( it != member.cend() )
{
member.erase(it);
}
}
void Notify()
{
for (auto &it : member)
{
if( NULL != it )
{
it->Updata(this);
}
}
}
void HasEvent(std::string bossEvent, std::string managerEvent, std::string HREvent)
{
this->bossEvent = bossEvent;
this->managerEvent = managerEvent;
this->HREvent = HREvent;
Notify();
}
std::string GetBossEvent()const
{
return bossEvent;
}
std::string GetMnagerEvent()const
{
return managerEvent;
}
std::string GetHREvent()const
{
return HREvent;
}
};
class Boss : public AbsObserver
{
private:
std::string plan;
public:
void Update(std::string report) //推送数据,推送方式下观察者不能选择性获取自己感兴趣的内容
{
plan = report;
std::cout << "Boss " << report << std::endl;
}
void Updata(AbsSubject * sj) //拉取数据,此方式可由观察者选择自己感兴趣的内容
{
if( Reception * re = dynamic_cast<Reception *>(sj) )
{
std::cout << "Boss " << re->GetBossEvent() << std::endl; //挑自己感兴趣的
}
}
};
class Manager : public AbsObserver
{
public:
void Update(std::string report)
{
std::cout << report << std::endl;
}
void Updata(AbsSubject * sj)
{
if (Reception * re = dynamic_cast<Reception *>(sj))
{
std::cout << "Manager " << re->GetMnagerEvent() << std::endl;
}
}
void DoSomething()
{
std::cout << "DoSomething" << std::endl;
}
};
class HR : public AbsObserver
{
public:
void Update(std::string report)
{
std::cout << report << std::endl;
}
void Updata(AbsSubject * sj)
{
if( Reception * re = dynamic_cast<Reception *>(sj) )
{
std::cout << "HR " <<re->GetHREvent() << std::endl;
}
}
void DoSomething()
{
std::cout << "DoSomething" << std::endl;
}
};
int main(int argc, char **argv)
{
Boss boss;
Secretary secretary(&boss);
Reception *reception = new Reception;
if( NULL == reception )
return -1;
Manager manager;
HR *hr = new HR;
if( NULL == hr )
return -1;
reception->RegisterObserver(&manager);
reception->RegisterObserver(hr);
reception->RegisterObserver(&boss);
hr->DoSomething();
secretary.SetPlan(std::string("phone call"));
reception->HasEvent(std::string("visit"), std::string("expressage"), std::string("interview"));
manager.DoSomething();
secretary.CancelObserver(&boss);
reception->CancelObserver(hr);
reception->CancelObserver(&manager);
reception->CancelObserver(&boss);
secretary.SetPlan(std::string("nothing"));
reception->HasEvent(std::string("nothing"), std::string("nothing"), std::string("nothing"));
delete reception;
delete hr;
return 0;
}