设计模式(十六)——观察者模式

一、观察者模式

1、观察者简介

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

wKioL1nUZjrxeuZxAAB6nmIUi_M628.jpg

    特点:将一个系统分割成一系列相互协作的类的副作用是需要维护相关对象间的一致性。

2、观察者角色

抽象主题(Subject)把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者。一般用接口或抽象类来实现抽象主题角色。

具体主题(Concrete Subject)在具体主题内部状态改变时,给所有登记过的观察者发出通知是抽象主题的子类(或实现)。

抽象观察者(Observer)为具体的观察者定义一个更新接口,在得到主题的通知时更新自己。

具体观察者(Concrete Observer):具体观察者实现抽象观察者角色所要求的更新接口,以便本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。

        Subject维护一个Observer列表,Subject执行notify()时就执行列表中的每个ObserverUpdate()。

3、观察者模式优缺点

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

4、观察者模式使用场景

观察者模式使用场景:

    当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。

二、观察者模式实现代码

Subject抽象主题类:

#ifndef SUBJECT_H
#define SUBJECT_H
#include <string>
#include <list>
#include <iostream>
#include <algorithm>
#include "Observer.h"
 
using namespace std;
 
//抽象主题
class Subject
{
public:
    virtual ~Subject()
    {
        //清除所有订阅者
        m_observers.clear();
    }
    //通知所有订阅者
    void notify()
    {
        list<Observer*>::iterator iter = m_observers.begin();
        for(; iter != m_observers.end(); iter++)
        {   //遍历订阅者链表,更新所有订阅者的状态
            (*iter)->update(this);
        }
    }
    //增加订阅者
    virtual void attach(Observer* ob)
    {
        m_observers.push_back(ob);
        cout << "attach an observer" << endl;
    }
    //删除订阅者
    virtual void detach(Observer* ob)
    {
        list<Observer*>::iterator iter;
        iter = find(m_observers.begin(), m_observers.end(), ob);
        if(iter != m_observers.end())
        {
            m_observers.erase(iter);
        }
        cout << "detach an observer." << endl;
    }
    //获取状态
    virtual string getState()
    {
        return m_state;
    }
    //设置状态
    virtual void setState(string state)
    {
        m_state = state;
    }
protected:
    Subject(){}
private:
    string m_state;//状态
    list<Observer*> m_observers;//订阅者链表
};
 
#endif // SUBJECT_H


 

ConcreteSubjectA具体主题类:

#ifndef CONCRETESUBJECTA_H
#define CONCRETESUBJECTA_H
#include "Subject.h"
 
//具体主题
class ConcreteSubjectA : public Subject
{
public:
    ConcreteSubjectA(){}
};
 
#endif // CONCRETESUBJECTA_H


 

ConcreteSubjectB具体主题类:

#ifndef CONCRETESUBJECTB_H
#define CONCRETESUBJECTB_H
#include "Subject.h"
 
//具体主题
class ConcreteSubjectB : public Subject
{
public:
    ConcreteSubjectB(){}
};
 
#endif // CONCRETESUBJECTB_H


 

Observer抽象观察者类:

#ifndef OBSERVER_H
#define OBSERVER_H
 
//抽象订阅者
class Subject;
class Observer
{
public:
    virtual ~Observer(){}
    //定义订阅者更新状态接口
    virtual void update(Subject* subject) = 0;
protected:
    Observer(){}
};
 
#endif // OBSERVER_H


ConcreteObserverA具体订阅者类:

#ifndef CONCRETEOBSERVERA_H
#define CONCRETEOBSERVERA_H
#include "Observer.h"
#include "Subject.h"
 
//具体订阅者
class ConcreteObserverA : public Observer
{
public:
    //实现订阅者更新状态接口
    virtual void update(Subject* subject)
    {
        m_state = subject->getState();//获取当前关注主题的状态
        cout << "ConcreteObserverA is " << m_state << endl;
    }
private:
    string m_state;
};
 
#endif // CONCRETEOBSERVERA_H


ConcreteObserverB具体订阅者类:

#ifndef CONCRETEOBSERVERB_H
#define CONCRETEOBSERVERB_H
#include "Observer.h"
#include "Subject.h"
 
//具体订阅者
class ConcreteObserverB : public Observer
{
public:
    //实现订阅者更新状态接口
    virtual void update(Subject* subject)
    {
        m_state = subject->getState();//获取当前关注主题的状态
        cout << "ConcreteObserverB is " << m_state << endl;
    }
private:
    string m_state;
};
 
#endif // CONCRETEOBSERVERB_H


客户调用程序:

#include "Observer.h"
#include "ConcreteObserverA.h"
#include "ConcreteObserverB.h"
#include "ConcreteSubjectA.h"
#include "ConcreteSubjectB.h"
 
int main()
{
    //订阅者
    Observer* observerA = new ConcreteObserverA();
    Observer* observerB = new ConcreteObserverB();
    //主题
    Subject* subjectA = new ConcreteSubjectA();
    Subject* subjectB = new ConcreteSubjectB();
    //添加订阅者到主题
    subjectA->attach(observerA);
    subjectA->attach(observerB);
 
    subjectB->attach(observerA);
    subjectB->attach(observerB);
 
    //设置主题状态
    subjectA->setState("SubjectA.");
    subjectB->setState("SubjectB");
    //通知订阅者
    subjectA->notify();
    //将订阅者从主题中删除
    subjectA->detach(observerB);
    //通知订阅者
    subjectA->notify();
    subjectB->notify();
    delete subjectA;
    delete subjectB;
 
    delete observerA;
    delete observerB;
 
    return 0;
}


三、观察者模式实例

wKioL1nUZmLyL3CfAADQFMI9S8s796.jpg

Subject抽象主题类:

#ifndef SUBJECT_H
#define SUBJECT_H
#include <iostream>
#include <string>
#include <list>
 
using namespace std;
class Observer;
//抽象主题类
class Subject
{
public:
    //获取状态
    string getState()
    {
        return m_state;
    }
    //设置状态
    void setState(string state)
    {
        m_state = state;
    }
    //增加订阅者接口
    virtual void attach(Observer* ob) = 0;
    //删除订阅者接口
    virtual void detach(Observer* ob) = 0;
    //主题状态发生变化时通知所有订阅者的接口
    virtual void notify() = 0;
    virtual void doAction() = 0;
protected:
    Subject(){}//不对外开放
protected:
    string m_state;//状态
    list<Observer*> m_observers;//订阅者链表
};
 
#endif // SUBJECT_H


BossComing具体主题类:

#ifndef BOSSCOMING_H
#define BOSSCOMING_H
#include "Subject.h"
#include "Observer.h"
 
//具体主题
class BossComing : public Subject
{
public:
    void attach(Observer* ob)
    {
        m_observers.push_back(ob);
    }
    void detach(Observer* ob)
    {
        std::list<Observer*>::iterator it;
        for(it = m_observers.begin(); it != m_observers.end(); it++)
        {
            if(**it == *ob)
            {
                m_observers.erase(it);
                break;
            }
        }
    }
    void notify()
    {
        list<Observer*>::iterator it;
        for(it = m_observers.begin();it != m_observers.end(); it++)
        {
            (**it).update();
        }
    }
    void doAction()
    {
        cout << "Check work." << endl;
    }
};
 
#endif // BOSSCOMING_H


Observer抽象订阅者类:

#ifndef OBSERVER_H
#define OBSERVER_H
#include "Subject.h"
 
//订阅者抽象类
class Observer
{
public:
    //订阅者更新接口
    virtual void update() = 0;
    bool operator==(const Observer& ob) const
    {
        return (m_name == ob.m_name) && (m_subject == ob.m_subject);
    }
protected:
    Observer(string name, Subject* subject)
    {
        m_name = name;
        m_subject = subject;
    }
protected:
    string m_name;//订阅者姓名
    Subject* m_subject;//订阅者关注的主题
};
 
#endif // OBSERVER_H


NBAObserver具体订阅者类:

#ifndef NBAOBSERVER_H
#define NBAOBSERVER_H
#include "Observer.h"
 
class NBAObserver : public Observer
{
public:
    NBAObserver(string name, Subject* subject):Observer(name, subject){}
    void update()
    {
        cout << m_subject->getState() << " " << m_name << " " 
             << "close NBA Live and continue to work." << endl;
        m_subject->doAction();
    }
};
 
#endif // NBAOBSERVER_H


 

StockObserver具体订阅者类:

#ifndef STOCKOBSERVER_H
#define STOCKOBSERVER_H
#include "Observer.h"
 
class StockObserver : public Observer
{
public:
    StockObserver(string name, Subject* subject):Observer(name, subject)
    {
    }
    void update()
    {
        cout << m_subject->getState() << " " << m_name << " " 
             << "close StockMarket View and continue to work." << endl;
        m_subject->doAction();
    }
};
 
#endif // STOCKOBSERVER_H


客户调用程序:

#include "Subject.h"
#include "BossComing.h"
#include "Observer.h"
#include "NBAObserver.h"
#include "StockObserver.h"
 
int main()
{
    Subject* boss = new BossComing();
 
    Observer* observerA = new NBAObserver("A", boss);
    Observer* observerB = new NBAObserver("B", boss);
    Observer* observerC = new StockObserver("C", boss);
    Observer* observerD = new StockObserver("D", boss);
 
    boss->attach(observerA);
    boss->attach(observerB);
    boss->attach(observerC);
    boss->attach(observerD);
 
    boss->setState("The Manager is coming.");
 
    boss->notify();
 
    boss->detach(observerD);
    boss->setState("The Boss is coming.");
    boss->notify();
 
    delete observerA,observerB,observerC,observerD;
    delete boss;
 
    return 0;
}