编程模式之观察者模式

编程模式大家都很熟悉,观察者模式也是经典中的经典,网络搜索观察者模式的实现代码也比比皆是,那么还有什么好说的呢。

这里我想实现的是一个能够广泛使用的观者者模式代码,也即拿来就能用,不用修改而且方便。目前常见的观察者模式大都是书写观者者和被观者者基类,完成观察、通知等操作。实际应用的时候,大都一个场景写一次,不能达到代码最大限度的复用思路。如下图(来源于网络):

主要问题出在Update,大部分情况,实现一个观察者模式,Update的时候都是要进行更新操作的,而更新操作时要看具体的ConcreateSubject的变化的,这个我们在写Subject类和Observer类的时候是无法预知的。所以这里Update无法传参,或者说无法传合适的参数能够达到代码写好就不再更改,而能满足各种情况的,话说这是模式6大原则中的哪条来着。或者Observer中记录着Subject的指针,Update的时候获取这一指针,然后据此获取ConcreateSubject的具体情况,这个貌似不错,只是也需要类型转换,而这样的做总是觉得不美的,Update是应用模式的关键代码位置,总是要继承重写的,能直接传过来需要的东西最好了。

说了半天,如何解决?不是说了要类型转换,然后不美么,解决类型问题即可。而提前预知子类类型好像也…,别忘记模板,写模板类可以提前定义类型,使用模板类完成观察者模式,一次编码,永久应用,且参数直接。不多说上代码:

// 观察者的抽象接口,实际的观察类根据需要继承CObserver和CMultiObserver

//

template<class T>

class  IObserver

{

public:

    IObserver(){}

    virtual  ~IObserver() {}

    typedef T  SubjectType;

    typedef IObserver<T> OBSERVER;

public:

    //Subject通知Observer更新

    friend  void  T::Notify();

    //用来在Subject中注册和解注册Observer

    friend  void  T::Attach(OBSERVER &Observer);

    friend  BOOL  T::Dettach(OBSERVER &Observer);

    friend  void  T::DetachAll();

protected

    //Observer根据Subject的变化更新

    virtual void  Update (T *pSubject) = 0;

    //用于被观察者进行回调的函数

    virtual void  Attach(T *pSubject)  = 0;

    virtual void  Dettach(T *pSubject) = 0;

};

// T为具体被观察者类型,具体Observer继承自Observer

// class ConcreteObserver : public Observer<Subject1>,public Observer<Subject2>

// {......} 

// 观察同一个类的单个实例,但是可以观察不同类的实例

//

template <class T>

class  CObserver : public IObserver<T>

{

public:

    CObserver():m_pSubject(NULL) {}

    virtual  ~CObserver();

protected

    //Observer根据Subject的变化更新

    virtual void  Attach(T *pSubject);

    virtual void  Dettach(T *pSubject);

public:

    //外界获取被观察的对象指针

    SubjectTypeGetSubject();

protected:

    SubjectTypem_pSubject;

};

//可以观察多个实例

//

template <class T>

class  CMultiObserver : public IObserver<T>

{

public:

    CMultiObserver(){}

    virtual  ~CMultiObserver();

    typedef vector<T*> Sub_vector;

    typedef typename Sub_vector::iterator Sub_Iter;

protected

    //Observer根据Subject的变化更新

    virtual void  Attach(T *pSubject);

    virtual void  Dettach(T *pSubject);

public:

    ///获取被观察的对象的迭代器

    Sub_Iter  SubBegin();

    Sub_Iter  SubEnd();

protected:

    //同一种类型的被观察者链表

    Sub_vector    m_Subjects;

};

// Subject 是被观察者的基类

// T是被观察者的具现类

// class ConcreateSubject : public Subject<ConcreateSubject>

// {........}

//

template <class T>

class  CSubject

{

public:

    CSubject() {}

    virtual ~CSubject();

    typedef  IObserver<T>   OBSERVER;

    typedef  vector<OBSERVER *>   Obs_Vector;

    typedef  typename  Obs_Vector::iterator Obs_Iterator;

public:

    //进行双向连接的和取消连接的接口

    void   Attach (OBSERVER &observer);

    BOOL   Dettach(OBSERVER &observer);

    void   DetachAll();

    //在被观察者被修改后调用,通知观察者

    void   Notify ();

    //遍历获取观察者的指针和个数

    int    GetObserverCount();

    OBSERVER * GetObserver(int iIndex);

private:

    //保存的所有的观察者的链表

    Obs_Vector  m_observers;

};

/

//函数的具体实现

//

//CObserver的实现函数

template<class T>

CObserver<T>::~CObserver()

{

    //通知被观察者,观察者退出了

    if(NULL != m_pSubject)

        m_pSubject->Dettach(*this);

}

template<class T>

void  CObserver<T>::Attach(T *pSubject)

{

    m_pSubject = pSubject;

}

template<class T>

void  CObserver<T>::Dettach(T *pSubject)

{

    ASSERT(m_pSubject == pSubject);

    m_pSubject = NULL;

}

template<class T>

TCObserver<T>::GetSubject()

{

    return m_pSubject;

}

//CMultiObserver的实现函数

template<class T>

CMultiObserver<T>::~CMultiObserver()

{

    //通知所有的被观察者,观察者退出了

    Sub_Iter iter = m_Subjects.begin();

    while (iter != m_Subjects.end())

    {

        //如果不能找到目标,消除

        (*iter)->Dettach(*this);

        iter = m_Subjects.begin();

    }

}

template <class T>

void  CMultiObserver<T>::Attach(T *pSubject)

{

    m_Subjects.push_back(pSubject);

}

template <class T>

void  CMultiObserver<T>::Dettach(T *pSubject)

{

    Sub_Iter iter = find(SubBegin(), SubEnd(), pSubject);

    if(iter != SubEnd())

    {

        m_Subjects.erase(iter);

    }

}

template <class T>

typename CMultiObserver<T>::Sub_Iter CMultiObserver<T>::SubBegin()

{

    return m_Subjects.begin();

}

template <class T>

typename CMultiObserver<T>::Sub_Iter CMultiObserver<T>::SubEnd() 

{

    return m_Subjects.end();

}

//CSubject的实现函数

//用static_cast取消观察是因为析构时对象已经不完整了

template<class T>

CSubject<T>::~CSubject()

{

    DetachAll();

}

template <class T>

void CSubject<T>::Attach (OBSERVER &observer)

{

    //实现Observer和Subject的双向关联

    m_observers.push_back(&observer);

    observer.Attach(dynamic_cast<T*>(this));

}

template <class T>

BOOL CSubject<T>::Dettach(OBSERVER &observer)

{

    //取消指定的Observer和Subject的双向连接

    Obs_Iterator iter = find(m_observers.begin(),m_observers.end(),&observer);

    //是否要对m_observers为空删除自身

    if(iter == m_observers.end())

        return  FALSE;

    m_observers.erase(iter);

    observer.Dettach(static_cast<T*>(this));

    return true;

}

template <class T>

void CSubject<T>::Notify ()

{

    //通知所有的观察者,被观察者被改变了

    for_each(m_observers.begin(),

        m_observers.end(),

        bind2nd(mem_fun(&IObserver<T>::Update),dynamic_cast<T *>(this)));

}

template <class T>

int CSubject<T>::GetObserverCount()

{

    return  (int)m_observers.size();

}

template <class T>

typename CSubject<T>::OBSERVER * CSubject<T>::GetObserver(int iIndex)

{

    return m_observers[iIndex];

}

template <class T>

void  CSubject<T>::DetachAll()

{

    //取消指定的Observer和Subject的双向连接

    for_each(m_observers.begin(),

        m_observers.end(),

        bind2nd(mem_fun(&IObserver<T>::Dettach), static_cast<T *>(this)));

    //最后清空连接

    m_observers.clear();

}

应用实例:

class ASubject : public CSubject<ASubject>

{

//这里只需要写ASubject的东西,不用管被观察者这个角色的内容

}

Class BObserver : public CObserver<ASubject>

{

 public:

/*这里,只需要继承CObserver<ASubject>的虚函数update,并且传参直接是ASubject指针,BObserver可以直接根据ASubject的情况进行自己的操作*/

 virtual void Update(ASubject *subject);

}

实现调用:

ASubject a;

BObserver b;

a.Attach(b);

/*a的任意操作*/

a.Notify();//通知b,a更改了

这样,完成了观察者模式的调用,并且,实际应用的代码非常简单,几乎只用关心Update接口的实现,而且,Update中已经把ConcreateSubject指针传过来了。不用再进行恶心的类型转换。

这段代码几乎可以不用修改的适用于任何情况的观察者模式应用场景了。

不过,我已经很久不用这个模式了,从这个模式,我发展了一种消息树模式,可以覆盖观察者模式,而且更方便,更强大,适应范围更广,再写吧。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值