• 20 行为型模式-----观察者模式


    模式动机(Observer Pattern)将数据的存储与显示进行分离设计,能够很好地降低模块直接的耦合性。但是我们在后台更新数据时总希望前台的显示也做出相应的变化,观察者模式很好地解决了这个问题。

    观察者模式定义了对象之间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动更新状态,即对于一份后台数据,可以存在多个显示器负责显示并同时接收后台数据变更的通知。

    观察者模式包含如下参与者:

    Subject:

    1> 可以有任意多个观察者同时观察同一目标

    2> 可以添加观察者、删除观察者

    Observer:

    1>  为那些在目标发生改变时需要得到通知的对象定义一个更新接口

    ConcreteSubject:

    1> 将当前状态subjectState存到具体观察者ConcreteObserver中

    2>  当状态发生改变时,及时通知各个观察者更新状态

    ConcreteObserver:

    1> 维护一个指向ConcreteSubject对象的指针subject

    2> 存储有关状态observerState,该状态应该与具体目标的状态subjectState保持一致

     

    当ConcreteSubject中的状态发生改变时,其会通知ConcreteObserver更新状态以保持状态的一致性。一个目标可以存在任意个观察者对象,一旦目标的状态发生改变,所有的观察者都会接到通知,但是目标对象可以不关心到底谁是它的观察者,其只需要调用Notify()就可以了。

     

    模式结构图:

     

    模式代码:

    bt_观察者模式.h:

     1 #ifndef OP_H
     2 #define OP_H
     3 #include <iostream>
     4 #include <list>
     5 using namespace std;
     6 
     7 /*
     8     抽象观察者:
     9     1> 为那些在目标发生改变时需要得到通知的对象定义一个更新接口
    10 */
    11 class Subject;
    12 class Observer
    13 {
    14 public:
    15     virtual ~Observer(){ }
    16     virtual void Update() = 0;
    17 };
    18 
    19 /*
    20     抽象目标:
    21     1> 可以有任意多个观察者同时观察同一目标
    22     2> 可以添加观察者、删除观察者
    23 */
    24 class Subject
    25 {
    26 public:
    27     Subject(){ observers = new list<Observer*>; }
    28     virtual ~Subject(){ delete observers; }
    29     void Attach(Observer* obv)
    30     {
    31         cout << "添加具体观察者" << endl;
    32         observers->insert(observers->end(), obv);
    33     }
    34     void Detach(Observer* obv)
    35     {
    36         cout << "删除具体观察者" << endl;
    37         delete obv;
    38         observers->remove(obv);
    39     }
    40     void Notify()
    41     {
    42         cout << "通知具体观察者更新状态->" << endl;
    43         list<Observer*>::iterator iter;
    44         for(iter = observers->begin(); iter != observers->end(); iter++)
    45         {
    46             (*iter)->Update();
    47         }
    48     }
    49 
    50 private:
    51     list<Observer*>* observers;
    52 };
    53 
    54 /*
    55     具体目标:
    56     1> 将当前状态subjectState存到具体观察者ConcreteObserver中
    57     2> 当状态发生改变时,及时通知各个观察者更新状态
    58 */
    59 class ConcreteSubject : public Subject
    60 {
    61 public:
    62     int GetState(){ return subjectState; }
    63     void SetState(int s)
    64     {
    65         subjectState = s;
    66         Notify();      // 通知所有观察者更新状态
    67     }
    68 
    69 private:
    70     int subjectState;
    71 };
    72 /*
    73     具体观察者:
    74     1> 维护一个指向ConcreteSubject对象的指针subject
    75     2> 存储有关状态observerState,该状态应该与具体目标的状态subjectState保持一致
    76 */
    77 class ConcreteObserver : public Observer
    78 {
    79 public:
    80     ConcreteObserver(ConcreteSubject* cs, int state) : subject(cs), observerState(state){}
    81     virtual void Update()
    82     {
    83         cout << "->具体观察者更新状态" << endl;
    84         cout << "更新前状态为:" << observerState << endl;
    85         observerState = subject->GetState();
    86         cout << "更新后状态为:" << observerState << endl;
    87     }
    88 
    89 private:
    90     ConcreteSubject* subject;
    91     int observerState;
    92 };
    93 
    94 #endif // OP_H

    测试用例.cpp:

     1 #include "bt_观察者模式.h"
     2 
     3 int main()
     4 {
     5 
     6     cout << "***** 观察者模式测试 *****" << endl;
     7     ConcreteSubject* cs = new ConcreteSubject;
     8     Observer* observer1 = new ConcreteObserver(cs, 6666);
     9     Observer* observer2 = new ConcreteObserver(cs, 7777);
    10     cs->Attach(observer1);  // 注册观察者
    11     cs->Attach(observer2);    // 注册观察者
    12     cs->SetState(8888);
    13 
    14                 // cs->Notify();     // 由客户调用Notify
    15 
    16     delete observer2;
    17     delete observer1;
    18     delete cs;
    19 
    20     return 0;
    21 }
    
    

    模式分析:

    :: 观察者模式将众多观察者和其依赖的具体目标进行解耦,使得每个目标仅知道存在观察者,但是不知道具体观察者是什么类型的。

    :: 目标发送通知时使用广播方式,凡是被登记过的观察者都会接收到并及时更新状态。

    :: Notify()函数由谁来调用呢?

    如果是由具体目标对象调用Notify(),那么必须每改变一次状态,就调用一次Notify()。但是,如果让客户负责调用Notify(),虽然可以对于多次改变只调用一次Notify(),但是可能容易忘记调用,导致丢失状态。上例中就是由具体目标负责调用Notify的例子,如下所示为由客户调用Notify()的例子:

    ConcreteSubject::SetState(int s)中去掉Notify():

    void SetState(int s)

    {

        subjectState = s;

    }

    主程序中增加cs->Notify()语句即可,结果和上述完全相同。

    :: 当然也可以扩展目标的注册接口,使得不同类型的观察者只对特定类型的事件感兴趣,这样可以提高观察者更新状态的效率。当一种事件发生,目标仅通知那些注册为对该类事件感兴趣的观察者。

    :: 如果依赖关系比较复杂,比如一个观察者依赖多个具体目标,而每个具体目标又对应多个观察者,这种多对多的依赖关系可以由一个专门的中介者来处理。一般而言,这种类型的中介者只应该存在唯一实例,因此最好用单例来设计它。

     

     

     

  • 相关阅读:
    Hadoop书籍介绍
    WeakReference,SoftReference 和 PhatomReference 浅析
    如何在Java中定义常量(Constant)
    也谈谈Java的垃圾收集(garbage collection)
    csdn的新家
    安装和使用Oracle Instant Client 和 SQLPlus
    Perl中的grep和map
    用Devel::NYTProf 优化perl脚本性能
    DataBase
    Linux下配置listener和tns
  • 原文地址:https://www.cnblogs.com/benxintuzi/p/4575245.html
Copyright © 2020-2023  润新知