一,简介
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
二,角色
Observer
抽象观察者,为所有的具体观察者定义一个借口,在得到主题的通知时更新自己
ConcreteObserver
具体观察者,实现抽象观察者所要求的更新接口,以便使本身的状态与主题的状态相协调
Subject
它把所有对观察者的引用保存在一句聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者
ConcreteSubject
具体主题,将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知
三,举例
上班摸鱼,如果老板过来,让前台负责通知
1,类图
2,代码
#include <list>
using namespace std;
class Observer;
//抽象通知者
class Subject {
protected:
list<Observer*> observers;
public:
string action;
virtual void attach(Observer*) = 0;
virtual void detach(Observer*) = 0;
virtual void notify() = 0;
};
//具体通知者 秘书
class Secretary :public Subject {
public:
void attach(Observer* observer) {
observers.push_back(observer);
}
void detach(Observer *observer) {
list<Observer*>::iterator iter = observers.begin();
while (iter != observers.end())
{
if ((*iter) == observer)
observers.erase(iter);
}
++iter;
}
void notify();
};
//抽象观察者
class Observer {
protected:
string name;
Subject *sub;
public:
Observer(string _name, Subject* _sub) {
this->name = _name;
this->sub = _sub;
}
virtual void update() = 0;
};
//具体观察者 看股票的
class StockObserver :public Observer {
public:
StockObserver(string _name,Subject* _sub):Observer(_name,_sub){}
void update() {
cout << name << " 收到消息:" << this->sub->action << endl;
if (this->sub->action == "老板来了") {
cout << "关闭股票,装作认真工作" << endl;
}
}
};
//具体观察者 看NBA的
class NBAObserver :public Observer {
public:
NBAObserver(string _name,Subject* _sub):Observer(_name,_sub){}
void update() {
cout << name << " 收到消息:" << sub->action << endl;
if (sub->action == "老板来了") {
cout << "关闭NBA,装作认真工作" << endl;
}
}
};
//此处一定要写在 .cpp 中,因为前置声明只能作为指针或引用,不能定义类的对象,自然也就不能调用对象中的方法了
void Secretary::notify() {
list<Observer*>::iterator iter = observers.begin();
while (iter != observers.end())
{
(*iter)->update();
++iter;
}
}
int main()
{
Subject *sub = new Secretary();//创建观察者
Observer* serverOne = new NBAObserver("小A", sub);
Observer* serverTwo = new StockObserver("小B", sub);
sub->attach(serverOne);
sub->attach(serverTwo);
sub->action = "老板来了";//事件
sub->notify();//通知
system("pause");
return 0;
}
四,优缺点
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
五,使用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
如:拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价