观察者模式

描述

观察者模式就是MVC模式中的View部分,所以应用也比较多。观察者模式定义了一种一对多的依赖关系,当一个对象的状态改变时,就自动通知并更新依赖关系。其实观察者这种一对多的关系就像拍卖。每个竞标者都有一个编号牌用来竞价。一旦拍卖开始,当一个竞标者(Observer)举牌,拍卖人(Subject)就会提高出价,并将新的价格告诉所有的竞标者(Observer)已进行新一轮的竞价。
image

结构

Subject为独立的抽象对象,Observer为用户接口。Subject提示Observer去做什么,而Observer就可以回调给Subject需要的信息。

image

具体操作

  1. 区分独立的功能和公共的功能
  2. 将独立功能建模为Subject
  3. 将公共的功能建模为Observer结构
  4. Subject只与Observer基类耦合
  5. 客户端配置观察者们
  6. 观察者们注册到Subject
  7. Subject广播事件到所有已经注册的观察者们
  8. Subject会将信息推送给观察者们,而观察者们会从中选取它们需要的信息

案例

1. 对比案例

  • 没有应用观察者模式
class DivObserver
{
    int m_div;
  public:
    DivObserver(int div)
    {
        m_div = div;
    }
    void update(int val)
    {
        cout << val << " div " << m_div << " is " << val / m_div << '\n';
    }
};

class ModObserver
{
    int m_mod;
  public:
    ModObserver(int mod)
    {
        m_mod = mod;
    }
    void update(int val)
    {
        cout << val << " mod " << m_mod << " is " << val % m_mod << '\n';
    }
};

class Subject
{
    int m_value;
    DivObserver m_div_obj;
    ModObserver m_mod_obj;
  public:
    Subject(): m_div_obj(4), m_mod_obj(3){}
    void set_value(int value)
    {
        m_value = value;
        notify();
    }
    void notify()
    {
        m_div_obj.update(m_value);
        m_mod_obj.update(m_value);
    }
};

int main()
{
  Subject subj;
  subj.set_value(14);
}
Output
14 div 4 is 3
14 mod 3 is 2
  • 应用观察者模式
#include <iostream>
#include <vector>
using namespace std;

class Observer
{
  public:
    virtual void update(int value) = 0;
};

class Subject
{
    int m_value;
    vector< Observer * > m_views;
  public:
    void attach(Observer *obs)
    {
        m_views.push_back(obs);
    }
    void set_val(int value)
    {
        m_value = value;
        notify();
    }
    void notify()
    {
        for (int i = 0; i < m_views.size(); ++i)
          m_views[i]->update(m_value);
    }
};

class DivObserver: public Observer
{
    int m_div;
  public:
    DivObserver(Subject *model, int div)
    {
        model->attach(this);
        m_div = div;
    }
     /* virtual */void update(int v)
    {
        cout << v << " div " << m_div << " is " << v / m_div << '\n';
    }
};

class ModObserver: public Observer
{
    int m_mod;
  public:
    ModObserver(Subject *model, int mod)
    {
        model->attach(this);
        m_mod = mod;
    }
     /* virtual */void update(int v)
    {
        cout << v << " mod " << m_mod << " is " << v % m_mod << '\n';
    }
};

int main()
{
  Subject subj;
  DivObserver divObs1(&subj, 4);
  DivObserver divObs2(&subj, 3);
  ModObserver modObs3(&subj, 3);
  subj.set_val(14);
}
Output
14 div 4 is 3
14 div 3 is 4
14 mod 3 is 2

2.Class inheritance VS type inheritance

#include <iostream>
#include <vector>
using namespace std;

class AlarmListener
{
  public:
    virtual void alarm() = 0;
};

class SensorSystem
{
    vector < AlarmListener * > listeners;
  public:
    void attach(AlarmListener *al)
    {
        listeners.push_back(al);
    }
    void soundTheAlarm()
    {
        for (int i = 0; i < listeners.size(); i++)
          listeners[i]->alarm();
    }
};

class Lighting: public AlarmListener
{
  public:
     /*virtual*/void alarm()
    {
        cout << "lights up" << '\n';
    }
};

class Gates: public AlarmListener
{
  public:
     /*virtual*/void alarm()
    {
        cout << "gates close" << '\n';
    }
};

class CheckList
{
    virtual void localize()
    {
        cout << "   establish a perimeter" << '\n';
    }
    virtual void isolate()
    {
        cout << "   isolate the grid" << '\n';
    }
    virtual void identify()
    {
        cout << "   identify the source" << '\n';
    }
  public:
    void byTheNumbers()
    {
        // Template Method design pattern
        localize();
        isolate();
        identify();
    }
};
// class inheri.  // type inheritance
class Surveillance: public CheckList, public AlarmListener
{
     /*virtual*/void isolate()
    {
        cout << "   train the cameras" << '\n';
    }
  public:
     /*virtual*/void alarm()
    {
        cout << "Surveillance - by the numbers:" << '\n';
        byTheNumbers();
    }
};

int main()
{
  SensorSystem ss;
  ss.attach(&Gates());
  ss.attach(&Lighting());
  ss.attach(&Surveillance());
  ss.soundTheAlarm();
}
Output
gates close
lights up
Surveillance - by the numbers:
   establish a perimeter
   train the cameras
   identify the source
3.
#include <iostream>
#include <vector>
using namespace std;

class Subject {
    // 1. "independent" functionality
    vector < class Observer * > views; // 3. Coupled only to "interface"
    int value;
  public:
    void attach(Observer *obs) {
        views.push_back(obs);
    }
    void setVal(int val) {
        value = val;
        notify();
    }
    int getVal() {
        return value;
    }
    void notify();
};

class Observer {
    // 2. "dependent" functionality
    Subject *model;
    int denom;
  public:
    Observer(Subject *mod, int div) {
        model = mod;
        denom = div;
        // 4. Observers register themselves with the Subject
        model->attach(this);
    }
    virtual void update() = 0;
  protected:
    Subject *getSubject() {
        return model;
    }
    int getDivisor() {
        return denom;
    }
};

void Subject::notify() {
  // 5. Publisher broadcasts
  for (int i = 0; i < views.size(); i++)
    views[i]->update();
}

class DivObserver: public Observer {
  public:
    DivObserver(Subject *mod, int div): Observer(mod, div){}
    void update() {
        // 6. "Pull" information of interest
        int v = getSubject()->getVal(), d = getDivisor();
        cout << v << " div " << d << " is " << v / d << '\n';
    }
};

class ModObserver: public Observer {
  public:
    ModObserver(Subject *mod, int div): Observer(mod, div){}
    void update() {
        int v = getSubject()->getVal(), d = getDivisor();
        cout << v << " mod " << d << " is " << v % d << '\n';
    }
};

int main() {
  Subject subj;
  DivObserver divObs1(&subj, 4); // 7. Client configures the number and
  DivObserver divObs2(&subj, 3); //    type of Observers
  ModObserver modObs3(&subj, 3);
  subj.setVal(14);
}

Output

14 div 4 is 3
14 div 3 is 4
14 mod 3 is 2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值