观察者模式(发布/订阅模式)
1、背景
当我们在打团队游戏时,当你受到攻击需要队友帮忙时该怎么办?这时候就需要给你所有的队友发送一条你正在被攻击的消息。所有的队友会根据你发送的消息作出相应的动作。比如有团队意识来帮你,或者不帮你继续玩自己的。
这里面的队员就是该设计模式名字中的观察者。那么受到攻击的自己的是什么呢。被观察者?不,准确的我们称之为目标或者主题。
所以整个流程大概就是:当目标(主题)的状态发送改变时就会通知观察者,观察者根据自己的情况做出相应的动作。
2、定义
1、定义:
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
2、结构组成:
- 1、Subject(目标或主题):它是指被观察的对象。我们在主题中定义一个观察者集合。一个观察者对象可以接收任意多个观察者。同时提供了一系列的方法管理这些观察者。
- 比如attach添加观察者到集合中,detach从集合中剔除观察者。notify通知集合中的所有观察者。
- 2、ConcreteSubject(具体目标):它拥有自己的状态,当它的状态的改变时就会通知各个观察者。同时还实现了在目标类中定义的抽象逻辑方法(如果有的话)
- 3、Observer(抽象观察者) :它是一个接口,观察者将对观察目标状态的改变做出相应的反应 该接口定义了更新数据的方法update
4、ConcreteObserver(具体观察者):具体观察者中会维护一个指向具体目标对象的引用,它存储了具体观察者的状态,这些状态和具体目标的状态要保持一致。它实现了抽象观察者对象的updata方法。
3、特征
1、优点
- 1、观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
- 将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。而观察者模式的关键对象是主题Subject和观察者 Observer,一个 Subject可以有任意数目的依赖.
- 2、观察者模式满足开闭原则的要求,增加新的具体观察者无须修改原有的系统代码。
- 3、观察者模式支持广播通信,观察目标会向所有已注册的观察者发送通知,降低了一对多系统的设计难度。
2、缺点
- 1、如果一个观察目标对象有很多的直接观察者和间接观察者,那么所有的观察者接收到消息会耗费大量的时间。
- 2、如果观察者和被观察者之间存在循环依赖,那么观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
- 3、依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者
3、适用场景
- 1、 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。
- 2、 一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
4、应用
大话设计模式案例
- 1、抽象观察者模式案例
调用时序图:
#include <iostream>
#include <list>
using namespace std;
class Observer;
class Subject
{
public:
virtual void Attach(Observer *) = 0;
virtual void Detach(Observer *) = 0;
virtual void Notify() = 0;
virtual void SetState(int state) = 0;
protected:
std::list<Observer *> m_ObserverList;
int m_iState;
};
class Observer
{
public:
Observer(Subject* sub) :sub_obj(sub) {}
virtual void Update(int) = 0;
protected:
Subject* sub_obj;
};
class ConcreteObserver : public Observer
{
public:
ConcreteObserver(Subject* pSubject) : Observer(pSubject){}
void Update(int value)
{
cout << "ConcreteObserver get the update. New State:" << value << endl;
}
};
class ConcreteObserver2 : public Observer
{
public:
ConcreteObserver2(Subject* pSubject) : Observer(pSubject) {}
void Update(int value)
{
cout << "ConcreteObserver2 get the update. New State:" << value << endl;
}
};
class ConcreteSubject : public Subject
{
public:
void Attach(Observer *pObserver);
void Detach(Observer *pObserver);
void Notify();
void SetState(int state)
{
this->m_iState = state;
}
};
void ConcreteSubject::Attach(Observer *pObserver)
{
m_ObserverList.push_back(pObserver);
}
void ConcreteSubject::Detach(Observer *pObserver)
{
m_ObserverList.remove(pObserver);
}
void ConcreteSubject::Notify()
{
std::list<Observer *>::iterator it = m_ObserverList.begin();
while (it != m_ObserverList.end())
{
(*it)->Update(m_iState);
++it;
}
}
int main()
{
// Create Subject
Subject *pSubject = new ConcreteSubject();
// Create Observer
Observer *pObserver = new ConcreteObserver(pSubject);
Observer *pObserver2 = new ConcreteObserver2(pSubject);
// Change the state
pSubject->SetState(2);
// Register the observer
pSubject->Attach(pObserver);
pSubject->Attach(pObserver2);
pSubject->Notify();
// Unregister the observer
pSubject->Detach(pObserver);
pSubject->SetState(3);
pSubject->Notify();
delete pObserver;
delete pObserver2;
delete pSubject;
}
2、秘书监视老板,通知下属偷懒案例
#include <iostream>
#include <string>
#include <list>
using namespace std;
class Subject;
//抽象观察者
class Observer
{
protected:
string name;
Subject *sub;
public:
Observer(string name, Subject *sub)
{
this->name = name;
this->sub = sub;
}
virtual void update() = 0;
};
//具体的观察者,看股票的
class StockObserver :public Observer
{
public:
StockObserver(string name, Subject *sub) :Observer(name, sub)
{
}
void update();
};
//具体的观察者,看NBA的
class NBAObserver :public Observer
{
public:
NBAObserver(string name, Subject *sub) :Observer(name, sub)
{
}
void update();
};
//抽象通知者
class Subject
{
protected:
list<Observer*> observers;
public:
string action;
virtual void attach(Observer*) = 0;
virtual void detach(Observer*) = 0;
virtual void notify() = 0;
};
//具体通知者,秘书
class Secretary :public Subject
{
void attach(Observer *observer)
{
observers.push_back(observer);
}
void detach(Observer *observer)
{
list<Observer *>::iterator iter = observers.begin();
while (iter != observers.end())
{
if ((*iter) == observer)
{
observers.erase(iter);
}
++iter;
}
}
void notify()
{
list<Observer *>::iterator iter = observers.begin();
while (iter != observers.end())
{
(*iter)->update();
++iter;
}
}
};
void StockObserver::update()
{
cout << name << " 收到消息:" << sub->action << endl;
if (sub->action == "梁所长来了!")
{
cout << "我马上关闭股票,装做很认真工作的样子!" << endl;
}
}
void NBAObserver::update()
{
cout << name << " 收到消息:" << sub->action << endl;
if (sub->action == "梁所长来了!")
{
cout << "我马上关闭NBA,装做很认真工作的样子!" << endl;
}
}
int main()
{
Subject *dwq = new Secretary(); //创建观察者<br> //被观察的对象
Observer *xs = new NBAObserver("xiaoshuai", dwq);
Observer *zy = new NBAObserver("zouyue", dwq);
Observer *lm = new StockObserver("limin", dwq);
//加入观察队列
dwq->attach(xs);
dwq->attach(zy);
dwq->attach(lm);
//事件
dwq->action = "去吃饭了!";//通知
dwq->notify();
cout << endl;
dwq->action = "梁所长来了!";
dwq->notify();
return 0;
}
参考
1、https://www.jianshu.com/p/186a0041ac5b
2、https://www.cnblogs.com/carsonzhu/p/5770253.html
3、《大话设计模式 》