观察者模式
也叫做发布订阅模式(Publish/subscribe)
Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.
(定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。)
通用类图
被观察者抽象类
定义被观察者必须实现的职责,能够动态的增加、取消观察者,完成被观察者必须实现的职责:管理观察者并通知观察者
被观察者具体类
继承其抽象类,定义自己的业务逻辑,定义对哪些事件进行通知
观察者抽象类
观察者接收到消息后,对信息进行处理
观察者具体类
继承其抽象类,每个观察者收到信息后的处理不同,实现各自的逻辑
通用源码
//被观察者抽象类
class Subject {
public:
//增加观察者
void addObserver(Observer *ob) {
sob.insert(ob);
}
//删除观察者
void deleteObserver(Observer *ob) {
sob.erase(ob);
}
//通知观察者
void notifyObservers() {
for(auto ob : sob) ob->updated();
}
private:
//定义观察数组
set<Observer*> sob;
};
//被观察者具体类
class ConcreteSubject : public Subject {
public:
void doSomething() {
//do something
Subject::notifyObservers();
}
};
//观察者抽象类
class Observer {
public:
//更新方法
virtual void updated() = 0;
};
//观察者具体类
class ConcreteObserver : public Observer {
public:
void updated() override {
//收到消息,逻辑处理
}
};
优点
观察者和被观察者之间是抽象耦合,观察者和被观察者都非常容易扩展
建立一套触发机制,一个事物的改变引起其他事物的变化
缺点
需要考虑开发效率和运行效率
使用场景
关联行为场景
事件多级触发场景
跨系统的消息交换场景
注意事项
广播链的问题
当一个对象既是观察者又是被观察者,会导致逻辑比较复杂,可维护性变差
异步处理问题
当观察者非常多的时候,异步处理,需要考虑线程安全和队列的问题
示例代码
#include <iostream>
#include <string>
#include <thread>
#include <unistd.h>
#include <set>
using namespace std;
class IHanFeiZi {
public:
virtual void haveBreakfast() = 0;
virtual void haveFun() = 0;
};
/*
class HanFeiZi : public IHanFeiZi {
public:
void haveBreakfast() override {
cout << "HanFeiZi: have breakfast..." << endl;
isHavingBreakfast = true;
}
void haveFun() override {
cout << "HanFeiZi: have fun..." << endl;
isHavingFun = true;
}
void setHavingBreakfast(bool b) {isHavingBreakfast = b;}
bool getHavingBreakfast() {return isHavingBreakfast;}
void setHavingFun(bool b) {isHavingFun = b;}
bool getHavingFun() {return isHavingFun;}
private:
bool isHavingBreakfast = false;
bool isHavingFun = false;
};
class ILiSi {
public:
virtual void update(string) = 0;
};
class LiSi : public ILiSi {
public:
void update(string s) override {
cout << "LiSi: report:" << endl;
reportToQinShiHuang(s);
cout << "LiSi: over" << endl;
}
private:
void reportToQinShiHuang(string s) {
cout << s << endl;
}
};
class Spy{
public:
Spy(HanFeiZi &h, LiSi &l, string s):han(h), li(l), type(s) {
thread t(bind(&Spy::run, this));
t.detach();
}
void run() {
while(r) {
if(type == "breakfast") {
if(han.getHavingBreakfast()) {
li.update("have breakfast");
han.setHavingBreakfast(false);
}
}else {
if(han.getHavingFun()) {
li.update("have fun");
han.setHavingFun(false);
}
}
}
}
void setRun(bool b) {
r = b;
}
private:
bool r = true;
HanFeiZi& han;
LiSi& li;
string type;
};
*/
//modify
class Observer {
public:
virtual void update(string) = 0;
};
class Observable {
public:
virtual void addObserver(Observer*) = 0;
virtual void deleteObserver(Observer*) = 0;
virtual void notifyObservers(string) = 0;
};
class HanFeiZi_t : public Observable, public IHanFeiZi {
public:
void addObserver(Observer* ob) override {
sob.insert(ob);
}
void deleteObserver(Observer* ob) override {
sob.erase(ob);
}
void notifyObservers(string s) override {
for(auto ob : sob) ob->update(s);
}
void haveBreakfast() override {
cout << "HanFeiZi: have breakfast..." << endl;
notifyObservers("have breakfast");
}
void haveFun() override {
cout << "HanFeiZi: have fun..." << endl;
notifyObservers("have fun");
}
private:
set<Observer*> sob;
};
class LiSi : public Observer {
public:
void update(string s) override {
cout << "LiSi: report:" << endl;
reportToQinShiHuang(s);
cout << "LiSi: over" << endl;
}
private:
void reportToQinShiHuang(string s) {
cout << s << endl;
}
};
class WangSi : public Observer {
public:
void update(string s) override {
cout << "WangSi: report:" << endl;
reportToQinShiHuang(s);
cout << "WangSi: over" << endl;
}
private:
void reportToQinShiHuang(string s) {
cout << s << endl;
}
};
class LiuSi : public Observer {
public:
void update(string s) override {
cout << "LiuSi: report:" << endl;
reportToQinShiHuang(s);
cout << "LiuSi: over" << endl;
}
private:
void reportToQinShiHuang(string s) {
cout << s << endl;
}
};
int main() {
/*
LiSi l;
HanFeiZi h;
string s1 = "fun";
string s2 = "breakfast";
Spy fun(h, l, s1);
Spy breakfast(h, l, s2);
cout << "fun begin" <<endl;
h.haveFun();
sleep(1);
cout << "breakfast begin" << endl;
h.haveBreakfast();
sleep(1);
fun.setRun(0);
breakfast.setRun(0);
cout << "spy end" << endl;
*/
LiSi li;
LiuSi liu;
WangSi wang;
HanFeiZi_t ht;
ht.addObserver(&li);
ht.addObserver(&liu);
ht.addObserver(&wang);
ht.haveBreakfast();
ht.deleteObserver(&wang);
ht.haveFun();
return 0;
}