观察者模式简介
ROS系统的消息传递就是一种观察者模式,一个节点发布出消息,订阅此消息的节点会进入回调函数,并做出相应的动作。
观察者模式定义了一种一对多的依赖关系,当一个被观察对象发生变化时,所有依赖被观察对象的观察者均会被通知且自动更新状态,这种交互方式被称为发布-订阅模式。
观察者模式:定义对象之间的一种一对多的依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新。
观察者模式结构
观察者模式由观察者和观察目标组成,为便于扩展,两个角色都设计了抽象层。
- Subject(目标):是被观察的对象,目标中定义了一个观察者的集合,即一个目标可能会有多个观察者,通过attach()和detach()方法来增删观察者对象。目标声明了通知方法notify(),用于在自身状态发生改变时通知观察者。
- ConcreteSubject(具体目标):具体目标实现了通知方法notify(),同时具体目标有记录自身状态的属性和成员方法;
- Observer(观察者):观察者将对接收到的目标发生改变的通知做出自身的反应,抽象层声明了更新方法update();
- ConcreteObserver(具体观察者): 实现了更新方法update(),具体观察者中维护了一个具体目标对象的引用(指针),用于存储目标的状态。
观察者模式代码实例
#include <iostream>
#include <list>
using namespace std;
class Observer
{
public:
virtual void Update(int) = 0;
};
class Subject
{
public:
virtual void Attach(Observer *) = 0;
virtual void Detach(Observer *) = 0;
virtual void Notify() = 0;
};
class ConcreteObserver : public Observer
{
public:
ConcreteObserver(Subject *pSubject) : m_pSubject(pSubject) {
}
void Update(int value)
{
cout << " ConcreteObserver1 get the update. New State: " << value << endl;
}
private:
Subject *m_pSubject;
};
class ConcreteObserver2 : public Observer
{
public:
ConcreteObserver2(Subject *pSubject) : m_pSubject(pSubject) {
}
void Update(int value)
{
cout << " ConcreteObserver2 get the update. New State: " << value << endl;
}
private:
Subject *m_pSubject;
};
class ConcreteSubject : public Subject
{
public:
void Attach(Observer *pObserver);
void Detach(Observer *pObserver);
void Notify();
void SetState(int state)
{
m_iState = state;
}
private:
std::list<Observer *> m_ObserverList;
int m_iState;
};
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
ConcreteSubject *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;
}
观察者模式总结
观察者模式是一种使用频率非常高的设计模式,几乎无处不在。凡是涉及一对一、一对多的对象交互场景,都可以使用观察者会模式。比如购物车,浏览商品时,往购物车里添加一件商品,会引起UI多方面的变化(购物车里商品数量、对应商铺的显示、价格的显示等);各种编程语言的GUI事件处理的实现;所有的浏览器事件(mouseover,keypress等)都是使用观察者模式的例子。
优点:
- 观察者模式实现了稳定的消息更新和传递的机制,通过引入抽象层可以扩展不同的具体观察者角色;
- 支持广播通信,所有已注册的观察者(添加到目标列表中的对象)都会得到消息更新的通知,简化了一对多设计的难度;
- 符合开闭原则,增加新的观察者无需修改已有代码,在具体观察者与观察目标之间不存在关联关系的情况下增加新的观察目标也很方便。
缺点:
- 代码中观察者和观察目标相互引用,存在循环依赖,观察目标会触发二者循环调用,有引起系统崩溃的风险;
- 如果一个观察目标对象有很多直接和简介观察者,将所有的观察者都通知到会耗费大量时间。
适用环境:
- 一个对象的改变会引起其他对象的联动改变,但并不知道是哪些对象会产生改变以及产生什么样的改变;
- 如果需要设计一个链式触发的系统,可是使用观察者模式;
- 广播通信、消息更新通知等场景。