认识观察者模式
顾名思义, 所谓观察者模式, 既存在观察者必然存在被观察的对象。那么被观察的对象称之为主题, 即观察主题。 那么主题对象将对观察者进行管理。而观察者决定对什么主题感兴趣, 从而进行订阅, 同时可以取消订阅。
简单的说, 观察者模式中存在两个对象, 一个是主题对象, 一个是观察者对象。 而观察者对象通常为多个, 所以主题对象与观察者通常为“一对多”的关系。
应用场景
生活中,常见类似观察者模式的应用类似于:
- 报社或者杂志的出版方和订阅者。出版方为主题对象, 订阅者为观察者
- 收音机。 其中电台为主题对象, 而使用收音机的你为观察对象。
- 天气预报。 气象台为主题对象,查看天气预报的对象为观察者。
- 其他不胜枚举
凡是在一个场景中, 存在主题对象, 且存在观察者时。 请使用此设计模式。
实例及分析
本实例中, 直接拿订阅杂志作为实例讲解。订阅者为观察者, 杂志出版方为主题对象。 一旦订阅者订阅了杂志, 杂志发布方将定期向订阅者邮寄杂志。
下面我们站在各对象的角度进行实例分析。
对于杂志出版方, 他需要了解的信息是:
- 订阅者列表
- 订阅者都有一个地址(即接收订阅的接口)
出版方利用订阅者的地址进行杂志邮寄 ,即主题发布。 这是他唯一需要知道的。
而对于订阅者:
- 杂志的内容
- 订阅及取消订阅的方式
而订阅者关心的是杂志的内容, 因为杂志的内容而产生订阅的想法, 进而利用订阅的渠道(接口)进行杂志订阅。 同时, 当订阅者对杂志不再感兴趣, 再利用取消订阅渠道进行杂志退订。
另一种场景, 即杂志订阅者主动索取杂志, 而不是由杂志出版方或销售方进行杂志发布。即转被动变为主动。 这是观察者模式另一种的工作模式。
类设计
下面为一个基本的观察者模式:
下面为针对杂志订阅而设计的类图:
源码实现
#include <iostream>
#include <set>
#include <string>
template <typename TData, typename ...Args>
class ISubject;
template <typename TData, typename ...Args>
class IObserver
{
public:
virtual ~IObserver() = default;
public:
explicit IObserver(ISubject<TData, Args...>* subject)
{
subject->AddObserver(this);
}
virtual void Update(const TData& param, const Args& ...args) const = 0;
};
template <typename TData, typename ...Args>
class ISubject
{
public:
virtual ~ISubject() = default;
typedef IObserver<TData, Args...> TObserver;
public:
virtual void Notify(TData param, Args&&... args) const
{
for (auto& observer : _setObservers)
{
observer->Update(param, std::forward<Args>(args)...);
}
}
virtual bool AddObserver(TObserver* observer)
{
return _setObservers.insert(observer).second;
}
virtual void RemoveObserver(TObserver* observer)
{
auto iterFind = _setObservers.find(observer);
if (iterFind != _setObservers.end()){
_setObservers.erase(iterFind);
}
}
private:
std::set<TObserver*> _setObservers;
};
typedef ISubject<std::string> IMagazinePublisher;
typedef IMagazinePublisher::TObserver ISubscriber;
class CSubscriberA : public ISubscriber
{
public:
explicit CSubscriberA(IMagazinePublisher* subject)
: ISubscriber(subject)
{
}
virtual void Update(const std::string& magazine) const override
{
std::cout <<typeid(*this).name() << " receive magazine: " <<magazine.c_str() << std::endl;
}
};
class CSubscriberB : public ISubscriber
{
public:
explicit CSubscriberB(IMagazinePublisher* subject)
: ISubscriber(subject)
{
}
virtual void Update(const std::string& magazine) const override
{
std::cout <<typeid(*this).name() << " receive magazine: " <<magazine.c_str() << std::endl;
}
};
int main(int argc, char const *argv[])
{
IMagazinePublisher magazineSubject;
CSubscriberA observerA(&magazineSubject);
CSubscriberB observerB(&magazineSubject);
magazineSubject.Notify("人民司法");
return 0;
}
/*
输出:
class CSubscriberB receive magazine: 人民司法
class CSubscriberA receive magazine: 人民司法
*/
总结
终归, 观察模式中, 存在两个场景:
- 主题对象对主题信息进行发布, 而观察者仅仅被动接收主题对象发布的信息。
- 观察者主动索取主题信息, 主题对象提供最新主题信息予以观察者。