观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
典型使用情况:某个对象掌握数据,当数据更新时通知多个对象更新显示(参考MVC)。
在java内置的Observer模式中支持“push”和“pull”两种方式,一般好像push更多一点,下面就以push为例:
UML图:
依然上一段测试代码:
一般来讲,把主题(Subject)内的数据封装成一个Class对日后的改动影响会小一点,编写代码时要尽量考虑到日后的变化。这里我们使用了一个string类型的字符串做测试,但是还是得提出来。
观察者接口需要提供一个update()方法:
#include <iostream>
#include <algorithm>
#include <list>
using namespace std;
class Observer {
public:
virtual void update(string str) = 0;
};
然后是主题接口,主题能够注册和删除观察者,并且提供notifyObserver()函数提示所有观察者更新:
class Subject {
public:
virtual void registerObserver(Observer*) = 0;
virtual void removeObserver(Observer*) = 0;
virtual void notifyObserver() = 0;
};
我们假设有个Model实现了Subject:
Model内部存放了一个Observer*的list,用于管理每个注册进来的Observer,并在更新事件时对他们进行更新。
class Model : public Subject {
public:
Model(){
info = "i haven't data";
}
void registerObserver(Observer* o){
observers.push_back(o);
}
void removeObserver(Observer* o)
{
list<Observer*>::iterator it = find(observers.begin(), observers.end(), o);
if ( it != observers.end() )
observers.remove(o);
}
void notifyObserver(){
list<Observer*>::iterator it = observers.begin();
while(it != observers.end()) {
(*it)->update(info);
++it;
}
}
// 模拟数据发生改变
void dataChanged(){
info = "i have data now!";
notifyObserver();
}
private:
list<Observer*> observers;
string info;
};
接下来我们实现观察者,假设为View(通常会有多个观察者):
我们在构造函数中调用Subject的registerObserver将自己注册到主题中,这样主题在数据改变时就会调用View的update(),然后我们使用display()将这个数据显示出来。
class View : public Observer {
public:
View(Subject* s){
mySubject = s;
mySubject->registerObserver(this);
}
void update(string str)
{
data = str;
display();
}
void display()
{
cout << data << endl;
}
private:
Subject* mySubject;
string data;
};
OK,最后来测试一下:
int main()
{
Model *model = new Model();
View *view = new View(model);
model->dataChanged();
return 0;
}
以上所有代码可以放到main.cpp中直接运行,大家不要纠结这里面的内存泄露什么的。。你们懂的。。当然一般情况下可能是我们会创建多个不同的Observer对象,然后分别显示Subject中不同的数据,不过结构都大致类似啦~
最后我们在上篇博文的3个设计原则的基础上再加一条:
为交互对象之间的松耦合设计而努力。