概念
观察者模式又被称为发布-订阅模式(Publish-Subscribe)、模型-视图模式(Model-View)、源-监听器模式(Source-Listener)、从属者模式(Dependents)。
它属于行为型模式的一种。
观察者模式:定义对象之间一对多的依赖关系,使得一个对象的状态发生改变时,它的关联对象都得到通知并被自动更新。
一个对象状态改变时(目标对象Subject),所有依赖他的对象(观察者对象Observer)都得到通知并能够发生改变。
Subject(目标):是被观察的对象,目标中定义了一个观察者的集合,即一个目标可能会有多个观察者,通过attach()和detach()方法来增删观察者对象。目标声明了通知方法notify(),用于在自身状态发生改变时通知观察者。
ConcreteSubject(具体目标):具体目标实现了通知方法notify(),同时具体目标有记录自身状态的属性和成员方法;
Observer(观察者):观察者将对接收到的目标发生改变的通知做出自身的反应,抽象层声明了更新方法update();
ConcreteObserver(具体观察者): 实现了更新方法update(),具体观察者中维护了一个具体目标对象的引用(指针),用于存储目标的状态。
观察者模式是使用频率非常高的一个设计模式,特别是在UI更新上。凡是涉及一对多的对象交互场景,都可以使用观察者会模式。比如购物车,用户往购物车里添加一件商品,就会引起UI多方面的变化;各种编程语言的GUI事件处理的实现;所有的浏览器事件(mouseover,keypress等)都是使用观察者模式的例子。
代码
class Observer // 抽象观察者
{
public:
virtual void update() = 0;
};
class ConcreteObserver:public Observer // 具体观察者
{
public:
void update(){
// 实现响应更新方法 具体操作
}
};
class Subject // 抽象目标
{
public:
void attach(Observer* obs){
obsList.push_back(obs);
}
void detach(Observer* obs){
obsList.remove(obs);
}
virtual void notify() = 0;
protected:
list<Observer*> obsList; // 观察者列表
};
class ConcreteSubject :public Subject // 具体目标
{
public:
void notify(){
// 遍历通知观察者对象
for (int i = 0; i < obsList.size(); i++){
obsList[i]->update();
}
}
};
int main()
{
Subject *sub = new ConcreteSubject();
Observer *obs = new ConcreteObserver();
sub->attach(obs);
sub->notify();
return 0;
}
优点
观察者模式实现了稳定的消息更新和传递的机制,通过引入抽象层可以扩展不同的具体观察者角色;
支持广播通信,所有已注册的观察者都会得到消息更新的通知,简化了一对多设计的难度;
符合开闭原则,新增的观察者无需修改已有代码,在具体观察者ConcreteObserver与观察目标之间不存在关联关系的情况下,增加新的观察目标Subject很方便。
缺点
代码中观察者Observer和观察目标Subject相互引用,存在循环依赖,观察目标会触发二者循环调用,有引起系统崩溃的风险;
如果一个观察目标对象有很多直接和简介观察者,将所有的观察者都通知到会耗费大量时间。
适用环境
一个对象的改变会引起其他对象的改变,但并不知道是哪些对象会产生改变以及产生什么样的改变;
如果需要设计一个触发式的系统,可是使用观察者模式;如:广播通信、消息更新通知等场景。