观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监视某一个主题对象。这个主题对象的状态变化时,会通知所有的观察者对象,使他们能够自动更新自己的状态。
- 举个例子:观察者模式可以理解为, 在一个一对多的关系模式中, 例如一个微信公众号有多个关注用户,那么关注该微信公众号的微信用户就是观察者,微信公众号就是被观察者.
- 一个微信公众号会有多个关注用户,这就是其中的一对多的关系.然后当一个对象的状态发生改变就是说当被观察者(微信公众号)有了改变,例如添加了新的内容.这时候所有关注该公众号的微信用户就希望能得到通知.
- Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
- ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。具体观察者角色可以保存一个指向具体主题对象的引用。
C++程序
#include<iostream>
#include<list>
#include<algorithm>
#include<string>
using namespace std;
class Observer // 抽象观察者,为所有的观察者定义更新接口 (Update),当收到 Subject 的通知时,Observer 需要同步更新信息。
{
public:
virtual ~Observer() = default;
virtual void Update() = 0;
};
class Subject // 抽象主题类,也是抽象被观察者
{
public:
virtual ~Subject() = default;
virtual void Attach(Observer* observer) = 0;
virtual void Detach(Observer* observer) = 0;
virtual void Notify() = 0; //通知所有观察者
};
class ConcreteSubject : public Subject // 具体主题类,也是具体被观察者
{
private:
string subjectState;
list<Observer*> observers;
public:
void Attach(Observer* observer)override //添加观察者
{
observers.push_back(observer);
}
void Detach(Observer* observer)override // 删除观察者
{
if(!observers.empty())
{
for (auto it = observers.begin(); it != observers.end(); ++it)
{
if (*it == observer)
{
observers.erase(it);
break;
}
}
}
}
void Notify() override //通知所有观察者
{
if(!observers.empty())
{
for (auto item : observers)
{
item->Update(); // 更新当前具体主题对象的状态到所有观察者中
}
}
}
string GetSubjectState() //设置状态
{
return subjectState;
}
void SetSubjectState(string state) // 获得状态
{
subjectState = state;
}
};
class ConcreterObserver : public Observer
{// 具体观察者
private:
ConcreteSubject *m_subject;
string m_name;
public:
ConcreterObserver() = default;
ConcreterObserver(ConcreteSubject *subject, string name) : m_subject(subject),m_name(name) {}
void Update()override
{
// 具体主题对象状态发生改变时,观察者也发生改变。
auto observerState = m_subject->GetSubjectState();
cout << observerState << "," << m_name << "关闭股票行情,继续工作!" << endl;
}
};
int main()
{
ConcreteSubject *huhansan = new ConcreteSubject;
ConcreterObserver *tongshi1 = new ConcreterObserver(huhansan, "魏关姹");
ConcreterObserver *tongshi2 = new ConcreterObserver(huhansan, "易管察");
ConcreterObserver *tongshi3 = new ConcreterObserver(huhansan, "霍华德");
huhansan->Attach(tongshi1);
huhansan->Attach(tongshi2);
huhansan->Attach(tongshi3);
//魏关姹没有被老板通知到,减去。
huhansan->Detach(tongshi1);
huhansan->SetSubjectState("我胡汉三回来了!");
huhansan->Notify();
delete huhansan;
delete tongshi1;
delete tongshi2;
delete tongshi3;
huhansan = nullptr;
tongshi1 = tongshi2 = tongshi3 = nullptr;
system("pause");
return 0;
}
结果
优点
观察者模式解除了具体主题和具体观察者的耦合
- 由于主题接口仅仅依赖于观察者接口,因此具体主题只是知道它的观察者是实现观察者接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题接口,因此具体观察者只是知道它依赖的主题是实现主题接口的某个类的实例,但不需要知道具体是哪个类。
观察者和被观察者之间是抽象耦合的,容易扩展
- 观察者模式满足“开-闭原则”。主题接口仅仅依赖于观察者接口,这样,就可以让创建具体主题的类也仅仅是依赖于观察者接口,因此,如果增加新的实现观察者接口的类,不必修改创建具体主题的类的代码。同样,创建具体观察者的类仅仅依赖于主题接口,如果增加新的实现主题接口的类,也不必修改创建具体观察者类的代码。