Observer(观察者)模式

1.概述

一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力。当对象们连接在一起时,它们就可以相互提供服务和信息。

通常来说,当某个对象的状态发生改变时,你仍然需要对象之间能互相通信。但是出于各种原因,你也许并不愿意因为代码环境的改变而对代码做大的修改。也许,你只想根据你的具体应用环境而改进通信代码。或者,你只想简单的重新构造通信代码来避免类和类之间的相互依赖与相互从属。

2.问题

当一个对象的状态发生改变时,你如何通知其他对象?是否需要一个动态方案――一个就像允许脚本的执行一样,允许自由连接的方案?

3.解决方案

             观测模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

观测模式允许一个对象关注其他对象的状态,并且,观测模式还为被观测者提供了一种观测结构,或者说是一个主体和一个客体。主体,也就是被观测者,可以用来联系所有的观测它的观测者。客体,也就是观测者,用来接受主体状态的改变 观测就是一个可被观测的类(也就是主题)与一个或多个观测它的类(也就是客体)的协作。不论什么时候,当被观测对象的状态变化时,所有注册过的观测者都会得到通知。
观测模式将被观测者(主体)从观测者(客体)种分离出来。这样,每个观测者都可以根据主体的变化分别采取各自的操作。(观测模式和Publish/Subscribe模式一样,也是一种有效描述对象间相互作用的模式。)观测模式灵活而且功能强大。对于被观测者来说,那些查询哪些类需要自己的状态信息和每次使用那些状态信息的额外资源开销已经不存在了。另外,一个观测者可以在任何合适的时候进行注册和取消注册。你也可以定义多个具体的观测类,以便在实际应用中执行不同的操作。
将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了它们的可重用性。

4.适用性

在以下任一情况下可以使用观察者模式:
• 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
• 当对一个对象的改变需要同时改变其它对象 , 而不知道具体有多少对象有待改变。
• 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之 , 你不希望这些对象是紧密耦合的。

5.结构

6.模式的组成

观察者模式包含如下角色:
目标(Subject): 目标知道它的观察者。可以有任意多个观察者观察同一个目标。 提供注册和删除观察者对象的接口。
具体目标(ConcreteSubject):  将有关状态存入各ConcreteObserver对象。
观察者(Observer):  为那些在目标发生改变时需获得通知的对象定义一个更新接口。当它的状态发生改变时, 向它的各个观察者发出通知。
具体观察者(ConcreteObserver):   维护一个指向ConcreteSubject对象的引用。存储有关状态,这些状态应与目标的状态保持一致。实现O b s e r v e r的更新接口以使自身状态与目标的状态保持一致。

7.效果

Observer模式允许你独立的改变目标和观察者。你可以单独复用目标对象而无需同时复用其观察者, 反之亦然。它也使你可以在不改动目标和其他的观察者的前提下增加观察者。
下面是观察者模式其它一些优点:
1 )观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
2 )在观察目标和观察者之间建立一个抽象的耦合 :一个目标所知道的仅仅是它有一系列观察者 , 每个都符合抽象的Observer类的简单接口。目标不知道任何一个观察者属于哪一个具体的类。这样目标和观察者之间的耦合是抽象的和最小的。因为目标和观察者不是紧密耦合的, 它们可以属于一个系统中的不同抽象层次。一个处于较低层次的目标对象可与一个处于较高层次的观察者通信并通知它 , 这样就保持了系统层次的完整。如果目标和观察者混在一块 , 那么得到的对象要么横贯两个层次 (违反了层次性), 要么必须放在这两层的某一层中(这可能会损害层次抽象)。
3) 支持广播通信 :不像通常的请求, 目标发送的通知不需指定它的接收者。通知被自动广播给所有已向该目标对象登记的有关对象。目标对象并不关心到底有多少对象对自己感兴趣 ;它唯一的责任就是通知它的各观察者。这给了你在任何时刻增加和删除观察者的自由。处理还是忽略一个通知取决于观察者。
4) 观察者模式符合“开闭原则”的要求。
观察者模式的缺点
1) 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2) 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3) 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
4)  意外的更新 因为一个观察者并不知道其它观察者的存在 , 它可能对改变目标的最终代价一无所知。在目标上一个看似无害的的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。此外 , 如果依赖准则的定义或维护不当,常常会引起错误的更新 , 这种错误通常很难捕捉。
      简单的更新协议不提供具体细节说明目标中什么被改变了 , 这就使得上述问题更加严重。如果没有其他协议帮助观察者发现什么发生了改变,它们可能会被迫尽力减少改变。

8.实现

#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<<"ConcreteObserver 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;
}

9.与其他相关模式

1) 终结者模式Mediator: 通过封装复杂的更新语义 , ChangeManager充当目标和观察者之间的中介者。
2) 单间模式Singleton: ChangeManager可使用Singleton模式来保证它是唯一的并且是可全局访问
的。

10.总结与分析

通过Observer模式,把一对多对象之间的通知依赖关系的变得更为松散,大大地提高了程序的可维护性和可扩展性,也很好的符合了开放-封闭原则。

时间: 2024-11-04 08:03:49

Observer(观察者)模式的相关文章

Java设计模式(五) Observer(观察者)模式及Tomcat引申

基本概念 Observer 观察者模式(Observer Pattern)又称为发布订阅模式(Publish/subscribe) 定义对象间的一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并且自动更新 根据单一职责原则,每个类的职责是单一的,我们可以通过触发机制,形成一个触发链,把各个单一的职责串联成真实世界中的复杂的逻辑关系. 观察者模式的角色分工(JDK中提供了抽象接口的定义): Subject被观察者: 抽象类型,定义被观察者必须实现的职责,动态地增加和

Observer(观察者)模式

在多个对象之间建立一对多的关系,以便当一个对象状态改变的时候,其他所有依赖于这个对象的对象都能得到通知,并被自动更新. 适用情况: 当一个抽象模型有两个方面,其中一个方面依赖于另一方面.将这二者封装在独立的对象中以使它们可以各自独立地改变和复用. 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁. 调用setChanged()方法,触发继承自Observable类的Observers()方法将这次改变广播出去. no

设计模式之Observer(观察者)模式

需求: 有一个报社,用户可以随时订阅报纸,也可以随时取消订阅.当每天的新闻来的时候,报社用邮递员投递给订阅了报纸的用户.订阅者有老人.小孩和青年.   分析: 报社相当于被观察的对象,用户相当于观察者,一旦新闻有更新,报社就通知所有观察者.   类图:     扩展:  该类图使用的是"推"的方式将新闻推送给订阅者.还可以使用一种的"拉"的方式实现,在Update传递空参数,只是通知订阅者数据有更新,然后由订阅者自己去报社获取(GetNews).这种方式实现起来更麻

观察者(Observer)模式 * 委托事件

观察者(Observer)模式:定义了一种一对多的依赖关系.让多个观察者对象同时监听某一个主题对象.   这个主题对象发生变化时会通知所有观察者对象,使他们字段更新自己 /* * 抽象主题(Subject)角色:主题角色把所有对观察考对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者. 抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现. * 抽象观察者(Observer)角色:为所有的具体观察者定义

Design Pattern - Observer 观察者设计模式

Spy on enemy. 使用这个模式可以根据某些事件自动更新. 设计思路: 1 设计一个基类,作为需要观察一个时间行为的接口类 2 设计一个观察者类,可以观察所有基类的衍生类, 这里使用set来保存这些需要更新的类. 一个事件相当于一个函数,事件发生(调用函数)同时自动调用需要更新的函数动作. #pragma once #include <iostream> #include <string> #include <set> #include <vector&g

观察者(Observer)模式

1. 概述 有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 2. 解决的问题 将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性.我们不希望为了维持一致性而使各类紧密耦合,这样会给维护.扩展和重用都带来不便.观察者就是解决这类的耦合关系的. 3. 模式中的角色 3.1 抽象主题(Subject):它把所有观察者对象的引用保存

Observer 观察者

意图 定义对象间的一种一对多的依赖关系 ,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新. 动机 一致性,松耦合 需要维护相关对象间的一致性.我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了它们的可重用性. 比如:Excel中制作测试数据的折线图.饼状图和柱状图,以直观的表现出性能的变化.在实际操作时,我发现,如果我修改了一个数据,折线图.饼状图和柱状图就都发生了变换. 这一模式中的关键对象是目标(subject)和观察者(observer).一个目标可以有任意数

学习javascript设计模式之发布-订阅(观察者)模式

1.发布-订阅模式又叫观察者模式,它定义对象之间一种一对多的依赖关系. 2.如何实现发布-订阅模式 2-1.首先指定好发布者 2-2.给发布者添加一个缓冲列表,用户存放回调函数以便通知订阅者 2-3.最后发布消息时候,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数 例子: var salesOffice = {};salesOffice.clientList = [];salesOffice.listen = function(key,fn){    if(!this.clientL

Java观察者模式(Observer模式)

Java深入到一定程度,就不可避免的碰到设计模式(design pattern)这一概念,了解设计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广泛,遵循一定的编程模式,才能使自己的代码便于理解,易于交流,Observer(观察者)模式是比较常用的一个模式,尤其在界面设计中应用广泛,而本教程所关注的是Java在电子商务系统中应用,因此想从电子商务实例中分析Observer的应用. 虽然网上商店形式多样,每个站点有自己的特色,但也有其一般的共性,单就"

重温Observer模式--热水器·改

在 C#中的委托和事件 一文的后半部分,我向大家讲述了Observer(观察者)模式,并使用委托和事件实现了这个模式.实际上,不使用委托和事件,一样可以实现Observer模式.在本文中,我将使用GOF的经典方式,再次实现一遍Observer模式,同时将讲述在 C#中的委托和事件 一文中没有提及的推模式(Push)和拉模式(Pull). 设计思想概述 在 C#中的委托和事件 一文后半部分中我已经较详细的讲述了Observer设计模式的思想,所以这里仅简单的提及一下.Observer设计模式中实际