观察者模式,是我们在开发过程中经常会遇到或者使用的设计模式。
比较常见的,我们在GUI库里便能看到其身影,譬如:键盘敲击事件后,需要将这一事件通知到所有观测键盘事件的对象。但凡涉及到这种一对多的通知,基本上都是观察者模式的应用。
更详细的介绍请参考:
http://blog.csdn.net/blacklaw0/article/details/8870210
我们经常使用的开发库中经常会存在这种模式,但是实现方式却不尽相同。所以,了解c/c++语言下观察者模式的实现方式,对于我们学习和掌握各种开源库将非常有帮助。一旦了解到该模式的存在,对整个代码会更增加一层了解和信心。
下面,我以我所知道的几种方式来分别实现一个非常简单的观察者模式,以示语言特性和该模式的一些特征。
假设,Subject会接受整数A和B,同时该Subject绑定了若干个Observer,在接受到整数A和B之后,需要及时通知所有Observer(例子里作为观察者的Adder和Muler皆简单输出A和B的和以及乘积)
先看c风格的代码实现:
#include <stdio.h>
// c style
int Add(int iA, int iB)
{
printf("Add(%d,%d)=%d\n", iA, iB, iA + iB);
return iA + iB;
}
int Mul(int iA, int iB)
{
printf("Mul(%d,%d)=%d\n", iA, iB, iA * iB);
return iA * iB;
}
typedef int (*fpCallBack)(int iA, int iB);
int main()
{
fpCallBack fpcb[2] = {&::Add, &::Mul};
fpcb[0](1, 2);
fpcb[1](1, 2);
return 0;}
这种方式间接明了,一路了然。c的风格就是这样的,不同的人写一小段代码,可能都大同小异。
#include <stdio.h>
#include <vector>
// cpp style1
struct IObserver1
{
virtual int OnAB(int iA, int iB)=0;
};
struct Subject1
{
void AddObserver(IObserver1*pObserver)
{
m_vecObserver.push_back(pObserver);
}
void Notify(int iA, int iB)
{
for (unsigned i = 0; i < m_vecObserver.size(); ++i)
{
m_vecObserver[i]->OnAB(iA, iB);
}
}
std::vector<IObserver1*> m_vecObserver;
};
struct Adder1 : public IObserver1
{
virtual int OnAB(int iA, int iB)
{
printf("Add1(%d,%d)=%d\n", iA, iB, iA + iB);
return iA + iB;
}
};
struct Muler1 : public IObserver1
{
virtual int OnAB(int iA, int iB)
{
printf("Mul1(%d,%d)=%d\n", iA, iB, iA * iB);
return iA * iB;
}
};
int main()
{
Subject1 subj1;
Adder1 adder1;
Muler1 muler1;
subj1.AddObserver(&adder1);
subj1.AddObserver(&muler1);
subj1.Notify(1, 2);
return 0;
}
这个也是比较显而易见的方式,定义一个虚基类,各个观察者必须继承并实现该接口,以方便管理并及时收到通知。这种方式的可读性比较好,但是耦合性比较大。
再看一个c++实现的方式:
#include <stdio.h>
#include <vector>
// cpp style2
struct IObserver2
{
};
typedef int (IObserver2::*Ofp)(int iA, int iB);
struct Subject2
{
void AddObserver(IObserver2*pObj, Ofp fp)
{
m_vecpObj.push_back(pObj);
m_vecOfp.push_back(fp);
}
void Notify(int iA, int iB)
{
for (unsigned i = 0; i < m_vecpObj.size(); ++i)
{
(((IObserver2*)m_vecpObj[i])->*m_vecOfp[i])(iA, iB);
}
}
std::vector<void*> m_vecpObj;
std::vector<Ofp> m_vecOfp;
};
struct Adder2 : public IObserver2
{
int OnAB(int iA, int iB)
{
printf("Add2(%d,%d)=%d\n", iA, iB, iA + iB);
return iA + iB;
}
};
struct Muler2 : public IObserver2
{
int OnAB(int iA, int iB)
{
printf("Mul2(%d,%d)=%d\n", iA, iB, iA * iB);
return iA * iB;
}
};
int main()
{
Subject2 subj2;
Adder2 adder2;
Muler2 muler2;
subj2.AddObserver(&adder2, (Ofp)&Adder2::OnAB);
subj2.AddObserver(&muler2, (Ofp)&Muler2::OnAB);
subj2.Notify(1, 2);
return 0
}
这个方法是基于类的成员函数指针来实现的,同样是继承,但是并不要求Observer类必须实现制定的虚函数,只需要保证有相同的成员函数签名。一个Observer类甚至能容纳多个Observer方法。这种方式相对前一种方式更灵活一点,但是同样要求继承一个基类,还是有一定的耦合性。
再看最后一个,c++11的版本
// cpp11
typedef std::function<int(int, int)> IntOpFun;
struct Subject3
{
void AddObserver(IntOpFun of)
{
m_vecOf.push_back(of);
}
void Notify(int iA, int iB)
{
for (auto iter = m_vecOf.begin(); iter != m_vecOf.end(); ++iter)
{
(*iter)(iA, iB);
}
}
std::vector<IntOpFun> m_vecOf;
};
struct Adder3
{
int OnAB(int iA, int iB)
{
printf("Add3(%d,%d)=%d\n", iA, iB, iA + iB);
return iA + iB;
}
};
struct Muler3
{
int OnAB(int iA, int iB)
{
printf("Mul3(%d,%d)=%d\n", iA, iB, iA * iB);
return iA * iB;
}
};
int main()
{
Subject3 subj;
Adder3 adder;
Muler3 muler;
subj.AddObserver(std::bind(&Adder3::OnAB, &adder, std::placeholders::_1, std::placeholders::_2));
subj.AddObserver(std::bind(&Muler3::OnAB, &muler, std::placeholders::_1, std::placeholders::_2));
subj.Notify(1, 2);
return 0;
}
这种方式不需要继承基类,不需要实现指定接口,通过std:fuction和std::bind可以发挥出相当大的自由度。但是在代码易读性上有一定损失。