观察者模式
概述
观察者(Observer)模式
又名发布-订阅(Publish/Subscribe)模式
。GOF 给观察者模式如下定义:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依 赖于它的对象都得到通知并被自动更新。
面向对象设计的一个重要原则——单一职责原则。系统的每个对象应该 将重点放在问题域中的离散抽象上。因此理想的情况下,一个对象只做一件事情。这样在开发中也就带来了诸多的好处: 提供了重用性和维护性,也是进行重构的良好的基础。
因此几乎所有的设计模式都是基于这个基本的设计原则来的。
UML图
其中:
- 抽象目标角色(Subject): 目标角色知道它的观察者,可以有任意多个观察者观察同一个目标。并且提供注册和删除观察者对象的接口。目标角色往往由抽象类或者接口来实现。
- 抽象观察者角色(Observer): 为那些在目标发生改变时需要获得通知的对象定义一个更新接口. 抽象观察者角色主要由抽象类或者接口来实现。
- 具体目标角色(Concrete Subject): 将有关状态存入各个 Concrete Observer 对象。当它的状态发生改变时, 向它的各个观察者发出通知。
- 具体观察者角色(Concrete Observer): 存储有关状态,这些状态应与目标的状态保持一致。实现 Observer 的更新接口以使自身状态与目标的状态保持一致。在本角色内也可以维护一个指向 Concrete Subject 对象的引用。
实现 (c++)
观察者
// observer.hpp
#ifndef observer_hpp
#define observer_hpp
#include <string>
#include "log.hpp"
#include "subject.hpp"
class subject;
class observer {
public:
observer() {};
std::string state;
virtual void update(subject& subject);
};
class observer1 : public observer {
public:
observer1() {}
void update(subject& subject);
};
class observer2 : public observer {
public:
observer2() {}
void update(subject& subject);
};
#endif /* observer_hpp */
// observer.cpp
#include "observer.hpp"
void observer::update(subject& subject) {
Log::i("observer update");
}
void observer1::update(subject& subject) {
this->state = subject.get_state();
Log::i("observer1 update");
}
void observer2::update(subject& subject) {
this->state = subject.get_state();
Log::i("observer2 update");
}
被观察角色
// subject.hpp
#ifndef subject_hpp
#define subject_hpp
#include <vector>
#include <string>
#include "observer.hpp"
class observer;
class subject {
public:
void attach(observer* observer_instance);
void detach(observer* observer_instance);
void set_state(std::string state);
std::string get_state();
void notify();
~subject();
subject();
private:
std::vector<observer*> _observers;
std::string _state;
};
class subject1 : public subject {
public:
subject1() {}
};
class subject2 : public subject {
public:
subject2() {}
};
#endif /* subject_hpp */
// subject.cpp
#include "subject.hpp"
subject::subject() {
}
subject::~subject() {
}
void subject::set_state(std::string state) {
this->_state = state;
}
std::string subject::get_state() {
return this->_state;
}
void subject::attach(observer* observer_instance) {
Log::i("subject attach");
auto iter = find(_observers.begin(), _observers.end(), observer_instance);
if (iter == _observers.end()) {
this->_observers.push_back(observer_instance);
}
}
void subject::detach(observer* observer_instance) {
Log::i("subject detach");
auto iter = find(_observers.begin(), _observers.end(), observer_instance);
if (iter != _observers.end()) {
_observers.erase(iter);
}
}
void subject::notify() {
for (auto iter = _observers.begin(); iter != _observers.end(); ++iter) {
(*(*iter)).update(*this);
}
}
测试
// main.cpp
#include "subject.hpp"
using std::cout;
using std::endl;
int main() {
observer* ob1 = new observer1();
observer* ob2 = new observer2();
subject* sub1 = new subject1();
subject* sub2 = new subject2();
sub1->attach(ob1);
sub1->attach(ob2);
sub2->attach(ob1);
sub1->set_state("start");
sub1->notify();
// 检查结果
cout << "start both ob1 & ob2: " << endl;
cout << "ob1: " << ob1->state << "\tob2:" << ob2->state << endl;
cout << endl;
sub1->set_state("end");
sub1->detach(ob1);
sub1->notify();
cout << "end ob2: " << endl;
cout << "ob1: " << ob1->state << "\tob2:" << ob2->state << endl;
cout << endl;
return 0;
}
结果
subject attach
subject attach
subject attach
observer1 update
observer2 update
start both ob1 & ob2:
ob1: start ob2:startsubject detach
observer2 update
end ob2:
ob1: start ob2:end
note
两个互相引用的类的实现问题
╓ a.hpp ═
#include "b.hpp" class b;
╙ a.cpp
╓ b.hpp ═#include "a.hpp" class a;
╙ b.cpp
使用情景
- 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。