Observer 模式 (观察者模式 / 发布-订阅)
一个发布者(主题), 多个订阅者(观察者), 发布者发布消息通知所有订阅者.
例子
– 消息等发布-订阅
– MVC 是观察者模式的一种实现
– 常见的一个例子: 对同一组数据进行统计分析时候, 希望提供多种形式的表示,
(例如以表格进行统计显示, 柱状图统计显示和百分比统计显示等).
这些表示都依赖于同一组数据, 当数据改变的时候, 所有的统计的显示都能够改变.
认识观察者模式
认识观察者模式:
发布者(主题) + 订阅者(观察者) = 观察者模式:
观察者模式:
定义观察者模式
观察者模式 Observer pattern 定义了对象之间的一 (Subject or Topic) 对
多 (Observers) 的依赖关系.
这样一来, 当主题对象改变状态时, 它的所有依赖者都会收到通知并自动更新.
观察者模式 也称为发布-订阅 (Publish-Subscribe),
“主题 Subject” 就是消息的发布者(Publisher), “观察者 Observers”则是消息的订阅者
(Subscribers)
观察者模式应该可以说是应用最多, 影响最广的模式之一,
也是在大型系统开发过程中要用到的模式之一.
观察者的一个实例 Model / View / Control (MVC) 结构在系统开发架构设计中有着很重要的
地位和意义, MVC 实现了业务逻辑和表示层的解耦.
在 Java Struts 则提供和 MFC 中 Doc/View 结构类似的实现 MVC 的框架,
另外 Java 语言本身就提供了观察者模式的实现接口.
观察者模式类图示例
实现示例 1 分析
https://yuiwong.org/gitlab/cpp/cppprogdesipatt/tree/master/src/observer/example
/**
* 简单的观察者模式(主题 即发布者, 观察者即订阅者)实现
* g++ observer.cpp -std=c++11 -Wall -Wextra
*/
#include <iostream>
#include <memory>
#include <functional>
#include <set>
template<typename T> struct Observer;
/**
* @struct Subject
* A generic subject(i.e. publisher) implementation
*/
template<typename T>
struct Subject {
using ObserverConstPtr = std::shared_ptr<Observer<T> const>;
Subject() noexcept = default;
virtual ~Subject() noexcept = default;
virtual bool subscribe(ObserverConstPtr const& observer) noexcept;
virtual bool unsubscribe(ObserverConstPtr const& observer) noexcept;
virtual bool publish(std::shared_ptr<T const> const& message) const
noexcept;
protected:
virtual void notify() const noexcept;
std::set<ObserverConstPtr> observers;
mutable std::shared_ptr<T const> message;
};
/**
* @struct Observer
* Basic and generic observer(i.e. subscriber) implementation
*/
template<typename T>
struct Observer {
Observer(
std::function<void(std::shared_ptr<T const> const&)> const& callback)
noexcept;
protected:
Observer() noexcept = default;
public:
virtual ~Observer() noexcept = default;
virtual void update(std::shared_ptr<T const> const& message) const
noexcept;
protected:
std::function<void(std::shared_ptr<T const> const&)> callback;
};
template<typename T>
bool Subject<T>::subscribe(ObserverConstPtr const& observer) noexcept
{
if (observer) {
auto const ret = this->observers.insert(observer);
return ret.second;
}
return false;
}
template<typename T>
bool Subject<T>::unsubscribe(ObserverConstPtr const& observer) noexcept
{
auto const it = this->observers.find(observer);
if (it != this->observers.end()) {
this->observers.erase(observer);
return true;
}
return false;
}
template<typename T>
bool Subject<T>::publish(std::shared_ptr<T const> const& message) const
noexcept
{
if (message) {
this->message = message;
this->notify();
return true;
}
return false;
}
template<typename T>
void Subject<T>::notify() const noexcept
{
for (auto it = this->observers.cbegin(), end = this->observers.cend();
it != end; ++it) {
(*it)->update(this->message);
}
}
template<typename T>
Observer<T>::Observer(
std::function<void(std::shared_ptr<T const> const&)> const& callback)
noexcept: callback(callback) {}
template<typename T>
void Observer<T>::update(std::shared_ptr<T const> const& message) const
noexcept
{
if (this->callback) {
this->callback(message);
}
}
/// String subscriber
struct SSubsciber {
SSubsciber();
void callback(std::shared_ptr<std::string const> const& a);
protected:
static int nextIdx;
int idx;
};
int SSubsciber::nextIdx = 0;
SSubsciber::SSubsciber(): idx(SSubsciber::nextIdx++) {}
void SSubsciber::callback(std::shared_ptr<std::string const> const& a)
{
std::cout << "SSubsciber." << this->idx << ": " << *a << "\n";
}
struct SObserver: public Observer<std::string> {
SObserver(): Observer() {
this->Observer::callback = std::bind(
&SObserver::callback, this, std::placeholders::_1);
}
void callback(std::shared_ptr<std::string const> const& a) const {
std::cout << "SObserver: " << *a << "\n";
}
};
struct S2Observer: public Observer<std::string> {
S2Observer(): Observer() {
this->Observer::callback = std::bind(
&S2Observer::callback, this, std::placeholders::_1);
}
void callback(std::shared_ptr<std::string const> const& a) const {
std::cout << "S2Observer: " << *a << "\n";
}
};
int main()
{
Subject<std::string> sPublihser;
std::shared_ptr<Observer<std::string> const> const sSubsciber1(
new Observer<std::string>([](std::shared_ptr<
std::string const> const& a){
std::cout << "aSubsciber1: " << *a << "\n";
}));
std::shared_ptr<Observer<std::string> const> const sSubsciber2(
new Observer<std::string>([](std::shared_ptr<
std::string const> const& a){
std::cout << "aSubsciber2: " << *a << "\n";
}));
SSubsciber ss3;
SSubsciber ss4;
std::shared_ptr<Observer<std::string> const> const s3(
new Observer<std::string>(std::bind(
&SSubsciber::callback, &ss3, std::placeholders::_1)));
std::shared_ptr<Observer<std::string> const> const s4(
new Observer<std::string>(std::bind(
&SSubsciber::callback, &ss4, std::placeholders::_1)));
std::shared_ptr<SObserver const> const s5(new SObserver());
std::shared_ptr<S2Observer const> const s6(new S2Observer());
sPublihser.subscribe(sSubsciber1);
sPublihser.subscribe(sSubsciber2);
sPublihser.subscribe(s3);
sPublihser.subscribe(s4);
sPublihser.subscribe(s5);
sPublihser.subscribe(s6);
auto const msg1 = std::shared_ptr<std::string>(new std::string("aaa"));
auto const msg2 = std::shared_ptr<std::string>(new std::string("bbb"));
sPublihser.publish(msg1);
sPublihser.publish(msg2);
std::cout << "\n";
sPublihser.unsubscribe(sSubsciber1);
sPublihser.publish(msg1);
sPublihser.publish(msg2);
return 0;
}
这里的主题提供依赖于它的观察者的注册和注销操作,
并且提供了使得依赖于它的所有观察者的通知操作. 观察者则提供一个 update 操作.
在观察者模式的示例实现中主题维护一个 unordered_set 作为存储其所有观察者的容器,
每当调用 notify 操作就遍历 set 中的观察者对象, 广播通知观察者 (调用观察者的 update).
运行示例程序, 可以看到当主题发布 aaa 和 bbb 的时候,
所有观察者都收到了 aaa 和 bbb, 然后第一个观察者取消订阅后,
再次发布 aaa 和 bbb 时除了第一个观察者其他都收到了.