设计模式那点事–观察者模式

简单说吧,该模式就只有两种角色,观察者对象(主题)和被观察者对象(观察者)。主题接收被观察者,有更新就通知被观察者。根据依赖倒转原则高内聚低耦合的目标,我们分别对此增加两个抽象接口。

概念:
    观察者模式(Observer),又称发布\订阅模式(Publish\Subscribe)。它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

例子:
    一个鲜活简单的例子总能让人轻松地理解晦涩的概念。我们来看看一个关于汽车零件更换的例子。
    大家应该有听说过吧,日本丰田(Toyota)车厂先前由于油门踏板问题,宣布在美国、欧洲和中国回收逾9百万辆私家车及货车,并作零件的更换。这次事件无疑对丰田品牌造成了重大的打击。
    假设丰田的油门踏板的生产厂商和BMW,Ferrali和Benz一样,当油门踏板出现问题时,油门踏板厂商会发出一个正式的零件更换通知书,以上所有品牌的汽车都会收到同样的更新通知:更换油门踏板零件,以保证用户使用车辆的安全。
    以上可看出,油门踏板厂商发出通知更新,所有的汽车供应商就会收到通知并进行更新,就是观察者模式。

角色:
    简单说吧,该模式就只有两种角色,观察者对象(主题)和被观察者对象(观察者)。主题接收被观察者,有更新就通知被观察者。根据依赖倒转原则高内聚低耦合的目标,我们分别对此增加两个抽象接口。
1. 抽象主题(Subject):它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象;
2. 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。这里可指油门踏板厂商;
3. 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题的通知时更新自己;
4. 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。这里可指BMW,Ferrali和Benz。

UML图:
这里写图片描述

代码:

#pragma warning(disable:4786)

#include<iostream>
#include <vector>
#include <list>
#include <string>

using namespace std;

//具体观察者结构体
typedef struct ObserverItems
{
    string strName;
    Observer* pObserver;
}ObserverSets;

//抽象观察者
class Observer
{
public:
    virtual void Update()=0;
};

//抽象通知者
class Notice
{
public:
    virtual void AddObserver(ObserverSets* ob)=0;
    virtual void RemoveObserver(ObserverSets* ob)=0;
    virtual void Notify()=0;
};

//具体通知者
class ConcreteNotice:public Notice
{
public:
    virtual ~ConcreteNotice()
    {
        list<ObserverSets*>::iterator stIter;

        for (stIter=observers.begin(); stIter!=observers.end(); stIter++)
        {
            if ((*stIter)->pObserver!=NULL)
            {
                delete (*stIter)->pObserver;
                (*stIter)->pObserver=NULL;
            }

            if ((*stIter)!=NULL)
            {
                delete (*stIter);
                (*stIter)=NULL;
            }
        }
    }

public:
    string getState()
    {
        return m_noticeState;
    }

    void setState(string strState)
    {
        m_noticeState = strState;
    }

public:
    //增加观察者
    void AddObserver(ObserverSets* ob)
    {
        observers.push_back(ob);
    }

    //去除观察者
    void RemoveObserver(ObserverSets* ob)
    {
        list<ObserverSets*>::iterator stIter;

        for (stIter=observers.begin(); stIter!=observers.end(); )
        {
            if ((*stIter)->strName==ob->strName)
            {
                observers.erase(stIter);

                break;
            }
            else
            {
                ++stIter;
            }
        }
    }

    //通知更新
    void Notify()
    {
        list<ObserverSets*>::iterator stIter;

        for (stIter=observers.begin(); stIter!=observers.end(); stIter++)
        {
            (*stIter)->pObserver->Update();
        }
    }

private:
    string m_noticeState;
    list<ObserverSets*> observers;
};

//具体观察者
class ConcreteObserver:public Observer
{
public:
    ConcreteObserver(ConcreteNotice* notice, string name)
    {
        this->m_Notice = notice;
        this->m_strName = name;
    }

    void Update()
    {
        m_strObserverState = m_Notice->getState();
        cout<<"通知:"<<m_strName<<" 要更换:"<<m_strObserverState<<endl;
    }

private:
    string m_strName;
    string m_strObserverState;
    ConcreteNotice* m_Notice;
};


void main()
{
    ConcreteNotice* notice = new ConcreteNotice;
    ObserverSets* pObItem = new ObserverSets;
    Observer* pOb=NULL; 

    //添加BMW车观察者
    pOb = new ConcreteObserver(notice, "BMW车");
    pObItem->pObserver = pOb;
    pObItem->strName = "BMW车";
    notice->AddObserver(pObItem);

    //添加Ferrali车观察者
    pObItem = new ObserverSets;
    pOb = new ConcreteObserver(notice, "Ferrali车");
    pObItem->pObserver = pOb;
    pObItem->strName = "Ferrali车";
    notice->AddObserver(pObItem);

    //添加Benz车观察者
    pObItem = new ObserverSets;
    pOb = new ConcreteObserver(notice, "Benz车");
    pObItem->pObserver = pOb;
    pObItem->strName = "Benz车";
    notice->AddObserver(pObItem);

    //去除Benz车观察者
    notice->RemoveObserver(pObItem);

    notice->setState("轮胎");
    notice->Notify();

    delete notice;
    notice = NULL;

    return;
}

发散:
    我们知道实现C++的多态有三种方法:函数重载,模板函数和虚函数。虚函数实现的多态称为动态多态,上面代码有以下特点:
1. 子类的对象转换给父类的对象,我们称为向上转型。它是安全的,自动完成,并且会丢失子类型的信息;
2. 为了解决子类型信息丢失的问题(子类对象转换给父类),父类必须实现了一个虚函数;
3. 子类有完全相同的函数,覆盖重写父类的虚函数,这样便能实现动态多态了(否则只能用指针或引用了)。

应用场景:
1. 当一个对象改变的时候同时需要改变其他对象,而且也可以不知道具体有多少对象有待改变;
2. 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。

优点:
1. Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知;
2. 高内聚、低耦合,可各自独立改变。

缺陷:
1. 松偶合导致代码关系不明显,有时可能难以理解;
2. 如果一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值