编程模式大家都很熟悉,观察者模式也是经典中的经典,网络搜索观察者模式的实现代码也比比皆是,那么还有什么好说的呢。
这里我想实现的是一个能够广泛使用的观者者模式代码,也即拿来就能用,不用修改而且方便。目前常见的观察者模式大都是书写观者者和被观者者基类,完成观察、通知等 *** 作。实际应用的时候,大都一个场景写一次,不能达到代码最大限度的复用思路。如下图(来源于网络):
主要问题出在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
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
// {......}
// 观察同一个类的单个实例,但是可以观察不同类的实例
//
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
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
typedef 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
{
//通知被观察者,观察者退出了
if(NULL != m_pSubject)
m_pSubject->Dettach(*this);
}
template
void CObserver
{
m_pSubject = pSubject;
}
template
void CObserver
{
ASSERT(m_pSubject == pSubject);
m_pSubject = NULL;
}
template
T* CObserver
{
return m_pSubject;
}
//CMultiObserver的实现函数
template
CMultiObserver
{
//通知所有的被观察者,观察者退出了
Sub_Iter iter = m_Subjects.begin();
while (iter != m_Subjects.end())
{
//如果不能找到目标,消除
(*iter)->Dettach(*this);
iter = m_Subjects.begin();
}
}
template
void CMultiObserver
{
m_Subjects.push_back(pSubject);
}
template
void CMultiObserver
{
Sub_Iter iter = find(SubBegin(), SubEnd(), pSubject);
if(iter != SubEnd())
{
m_Subjects.erase(iter);
}
}
template
typename CMultiObserver
{
return m_Subjects.begin();
}
template
typename CMultiObserver
{
return m_Subjects.end();
}
//CSubject的实现函数
//用static_cast取消观察是因为析构时对象已经不完整了
template
CSubject
{
DetachAll();
}
template
void CSubject
{
//实现Observer和Subject的双向关联
m_observers.push_back(&observer);
observer.Attach(dynamic_cast
}
template
BOOL CSubject
{
//取消指定的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
return true;
}
template
void CSubject
{
//通知所有的观察者,被观察者被改变了
for_each(m_observers.begin(),
m_observers.end(),
bind2nd(mem_fun(&IObserver
}
template
int CSubject
{
return (int)m_observers.size();
}
template
typename CSubject
{
return m_observers[iIndex];
}
template
void CSubject
{
//取消指定的Observer和Subject的双向连接
for_each(m_observers.begin(),
m_observers.end(),
bind2nd(mem_fun(&IObserver
//最后清空连接
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指针传过来了。不用再进行恶心的类型转换。
这段代码几乎可以不用修改的适用于任何情况的观察者模式应用场景了。
不过,我已经很久不用这个模式了,从这个模式,我发展了一种消息树模式,可以覆盖观察者模式,而且更方便,更强大,适应范围更广,再写吧。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)