观察者模式有点像事件触发机制,也是一种回调机制,在观察者模式中,有观察者和被观察者,当被观察者有什么动静的时候,就可以以某种方式通知观察者做出某些动作,简单示例如下:
class Observer {
public:
virtual void update() = 0;
};
class Observer1 : public Observer {
public:
void update() { cout<<"Observer1 updating"<<endl; }
};
class Observable {
protected:
list<Observer*> ls;
public:
void addObserver(Observer *p) { ls.push_back(p); }
void noticeObserver();
};
Observer是观察者的基类,提供一些通用接口,派生的观察者(Observer1)可以重定义这些接口来执行特定的的响应动作。Observable是被观察者,它有一个list<Observer*>用于保存那些关注着它的观察者们,这些观察者可以通过addObserver()被添加进来,如果Observable有什么动静,就可以调用noticeeObserver来通知观察者们,noticeObserver的定义如下:
void Observable::noticeObserver() {
list<Observer*>::iterator it = ls.begin();
while(it!=ls.end()) {
(*it)->update();
it++;
}
};
在noticeObserver通过iterator一个一个地通知Observer,即调用Observer的update()。这是最简单直观的观察者模式,在《C++编程思想》中给出了一种基于内部类的观察者模式,注意这里是内部类而不是嵌套类,内部类是可以访问外围类私有成员的嵌套类,C++中没有直接支持内部类,我们可以通过简单的代码来实现一个内部类:
class Outer {
int i;
class Inner;
friend class Outer::Inner;
class Inner {
Outer *p;
public:
void func() { cout<<p->i<<endl; }
};
};
Inner保存着一个指向Outer的指针:p ,且Inner为Outer的友元,所以在Inner中可以通过p来访问Outer的私有成员(在C++中,嵌套类与外围类基本没有关系,除了嵌套类是在外围类中定义的,如果不是互为友元,外围类不可以访问嵌套类的私有成员,嵌套类也不可以访问外围类的私有成员)。下面我们基于内部类给出一个简单的事件触发机制:
class Observable {
protected:
list<Observer*> ls;
public:
void addObserver(Observer *p) { ls.push_back(p); }
void noticeObserver();
};
class Event {
bool isClicked;
bool isDoubleClicked;
public:
/* Inner class : ClickEvent */
class ClickEvent;
friend class Event::ClickEvent;
class ClickEvent : public Observable {
Event *p;
public:
ClickEvent(Event *q) : p(q) {}
void noticeObserver() {
if (!p->isClicked) return ;
list<Observer*>::iterator it = ls.begin();
while(it!=ls.end()) {
(*it)->update();
it++;
}
p->isClicked = false;
}
} clickEvent;
/* Inner class : DoubleClickEvent */
class DoubleClickEvent;
friend class Event::DoubleClickEvent;
class DoubleClickEvent : public Observable {
Event *p;
public:
DoubleClickEvent(Event *q) : p(q) {}
void noticeObserver() {
if (!p->isDoubleClicked) return ;
list<Observer*>::iterator it = ls.begin();
while(it!=ls.end()) {
(*it)->update();
it++;
}
p->isDoubleClicked = false;
}
} doubleClickEvent;
Event() : isClicked(false),isDoubleClicked(false),clickEvent(this),doubleClickEvent(this) {}
void setClick() {
isClicked = true;
clickEvent.noticeObserver();
}
void setDoubleClick() {
isDoubleClicked = true;
doubleClickEvent.noticeObserver();
}
};
代码有点长,不过很好理解,Event是事件的总称,里面既有单击事件(ClickEvent),也有双击事件(DoubleClickEvent),这两个事件都被定义成内部类(都保存一个指向Event的指针),单击事件有单击事件的Observer,双击事件有双击事件的Observer,所以如果发生了单击事件,就通知单击事件的Observer,否则通知双击事件的Observer。ClickEvent和DoubleEvent都是Observable的派生类。完整的观察者模式应该还有观察者,如下:
class Observer {
public:
virtual void update() { cout<<"updating"<<endl; }
};
class ClickObserver: public Observer {
public:
virtual void update() { cout<<"clicked"<<endl; }
};
class DoubleClickObserver: public Observer {
public:
void update() { cout<<"double clicked"<<endl; }
};
即定义两个观察者,ClickObserver对单击事件感兴趣,而DoubleClickObserver对双击事件感兴趣,下面给出一个使用上述事件触发机制的例子:
int main() {
Event e;
e.clickEvent.addObserver(new ClickObserver());
e.setClick();
e.doubleClickEvent.addObserver(new DoubleClickObserver());
e.setDoubleClick();
return 0;
}