编程模式之观察者模式

编程模式之观察者模式,第1张

编程模式观察模式

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

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

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

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

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

//

template

class  IObserver

{

public:

    IObserver(){}

    virtual  ~IObserver() {}

    typedef T  SubjectType;

    typedef IObserver 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,public Observer

// {......} 

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

//

template

class  CObserver : public IObserver

{

public:

    CObserver():m_pSubject(NULL) {}

    virtual  ~CObserver();

protected: 

    //Observer根据Subject的变化更新

    virtual void  Attach(T *pSubject);

    virtual void  Dettach(T *pSubject);

public:

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

    SubjectType*  GetSubject();

protected:

    SubjectType*  m_pSubject;

};

//可以观察多个实例

//

template

class  CMultiObserver : public IObserver

{

public:

    CMultiObserver(){}

    virtual  ~CMultiObserver();

    typedef vector 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

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

//

template

class  CSubject

{

public:

    CSubject() {}

    virtual ~CSubject();

    typedef  IObserver   OBSERVER;

    typedef  vector   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

CObserver::~CObserver()

{

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

    if(NULL != m_pSubject)

        m_pSubject->Dettach(*this);

}

template

void  CObserver::Attach(T *pSubject)

{

    m_pSubject = pSubject;

}

template

void  CObserver::Dettach(T *pSubject)

{

    ASSERT(m_pSubject == pSubject);

    m_pSubject = NULL;

}

template

T*  CObserver::GetSubject()

{

    return m_pSubject;

}

//CMultiObserver的实现函数

template

CMultiObserver::~CMultiObserver()

{

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

    Sub_Iter iter = m_Subjects.begin();

    while (iter != m_Subjects.end())

    {

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

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

        iter = m_Subjects.begin();

    }

}

template

void  CMultiObserver::Attach(T *pSubject)

{

    m_Subjects.push_back(pSubject);

}

template

void  CMultiObserver::Dettach(T *pSubject)

{

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

    if(iter != SubEnd())

    {

        m_Subjects.erase(iter);

    }

}

template

typename CMultiObserver::Sub_Iter CMultiObserver::SubBegin()

{

    return m_Subjects.begin();

}

template

typename CMultiObserver::Sub_Iter CMultiObserver::SubEnd() 

{

    return m_Subjects.end();

}

//CSubject的实现函数

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

template

CSubject::~CSubject()

{

    DetachAll();

}

template

void CSubject::Attach (OBSERVER &observer)

{

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

    m_observers.push_back(&observer);

    observer.Attach(dynamic_cast(this));

}

template

BOOL CSubject::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(this));

    return true;

}

template

void CSubject::Notify ()

{

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

    for_each(m_observers.begin(),

        m_observers.end(),

        bind2nd(mem_fun(&IObserver::Update),dynamic_cast(this)));

}

template

int CSubject::GetObserverCount()

{

    return  (int)m_observers.size();

}

template

typename CSubject::OBSERVER * CSubject::GetObserver(int iIndex)

{

    return m_observers[iIndex];

}

template

void  CSubject::DetachAll()

{

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

    for_each(m_observers.begin(),

        m_observers.end(),

        bind2nd(mem_fun(&IObserver::Dettach), static_cast(this)));

    //最后清空连接

    m_observers.clear();

}

应用实例:

class ASubject : public CSubject

{

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

}

Class BObserver : public CObserver

{

 public:

 virtual void Update(ASubject *subject);

}

实现调用:

ASubject a;

BObserver b;

a.Attach(b);

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

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

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

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

 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5690963.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存