观察者模式,用于多个对象关注同一个对象的变化的情况。
王泽宾大牛写的文章比较生动,我只是用自己的理解实现了一个版本,而已。http://blog.csdn.net/wanghao72214/article/details/4017507
一,经典一点的实现,当然subject应该有个get_state的虚接口比较正宗,为了简单就先这样吧:
#include <string>
#include <iostream>
#include <vector>
#include <list>
using namespace std;
class Subject;
class Observer{
public:
Observer(Subject &sbj_obj)
{
sbj = &sbj_obj;
}
~Observer(){}
virtual int update() = 0;
void set_name(string & strname){
name = strname;
}
string get_name(){
return name;
}
Subject * sbj;
string name;
};
class Subject{
public:
Subject(){
id = 0;
}
~Subject(){}
int attatch(Observer * obsv){
obsvs.push_back(obsv);
}
int dettatch(Observer * obsv){
obsvs.remove(obsv);
}
int notify(){
id++;
list<Observer *>::iterator iter = obsvs.begin();
for (;iter != obsvs.end(); iter++){
(*iter)->update();
}
}
int get_id(){
return id;
}
private:
int id;
list<Observer *> obsvs;
};
class Screen : public Observer{
public:
explicit Screen(Subject &sbj_obj):Observer(sbj_obj){}
Screen(Subject &sbj_obj, string & strname):Observer(sbj_obj){
set_name(strname);
}
~Screen(){}
int update(){
cout<<get_name()<<" screan updated, sig:"<<sbj->get_id()<<"!"<<endl;
return 0;
}
};
class Speeker : public Observer{
public:
Speeker(Subject &sbj_obj):Observer(sbj_obj){}
Speeker(Subject &sbj_obj, string & strname):Observer(sbj_obj){
set_name(strname);
}
~Speeker(){}
int update(){
cout<<get_name()<<" Speeker updated, sig:"<<sbj->get_id()<<"!"<<endl;
return 0;
}
};
int main(){
Subject sbj;
string scr1_name("scr1");
string scr2_name("scr2");
string spk1_name("spk1");
Screen * scr1 = new Screen(sbj, scr1_name);
Screen * scr2 = new Screen(sbj, scr2_name);
Speeker * spk1 = new Speeker(sbj, spk1_name);
sbj.attatch(scr1);
sbj.attatch(scr2);
sbj.attatch(spk1);
sbj.notify();
sbj.notify();
return 0;
}
/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
二、带模板参数的观察者
我是觉得被观察者,只是需要给观察者发布一些消息而已。没必要subjet耦合到observer中。每个observer可以处理不同的subject发过来的消息才对。
这样需要增加一个消息类型参数。当然模板参数也只是编译时的参数,通过继承可以做到一些更灵活的实现。但动态加载这块,如果没有反射机制估计不太好实现。
#include <string>
#include <iostream>
#include <vector>
using namespace std;
template <class sig_type>
class Observer{
public:
Observer(){}
~Observer(){}
virtual int update(sig_type &sig) = 0;
void set_name(string & strname){
name = strname;
}
string get_name(){
return name;
}
private:
string name;
};
class Counter{
public:
Counter(){
count = 0;
}
~Counter(){}
int attatch(Observer<int> * obsv){
observers.push_back(obsv);
return 0;
}
int dettatch(Observer<int> * obsv){
return 0;
//observer.
}
int notify(){
vector<Observer<int> *>::iterator iter = observers.begin();
for ( ; iter != observers.end(); iter++){
(*iter)->update(count);
}
return 0;
}
int add_count(){
return ++count;
}
int get_count(){
return count;
}
private:
vector<Observer<int> *> observers;
int count;
};
class Screen : public Observer<int>{
public:
explicit Screen(){}
Screen(string & strname){
set_name(strname);
}
~Screen(){}
int update(int &sig){
cout<<get_name()<<" screan updated, sig:"<<sig<<"!"<<endl;
return 0;
}
};
class Speeker : public Observer<int>{
public:
Speeker(){}
Speeker(string & strname){
set_name(strname);
}
~Speeker(){}
int update(int &sig){
cout<<get_name()<<" Speeker updated, sig:"<<sig<<"!"<<endl;
return 0;
}
};
int main(){
Counter * counter = new Counter();
string scr1_name("scr1");
string scr2_name("scr2");
string spk1_name("spk1");
Screen * scr1 = new Screen(scr1_name);
Screen * scr2 = new Screen(scr2_name);
Speeker * spk1 = new Speeker(spk1_name);
counter->attatch(scr1);
counter->attatch(scr2);
counter->attatch(spk1);
counter->notify();
counter->add_count();
counter->notify();
return 0;
}
这样实际上就不需要一个真正的subject对象了,而是定义一个消息类型即可。减少了一定的耦合。但是不知道有多少实用价值。
如果能做到动态加载不同的消息,我觉得比较理想。这样就从一个1:N关系,扩展到N:M关系,而且耦合也比较松。
后面再想想。