【设计模式】之观察者模式(Observer)

来源:互联网 发布:windows日志删除记录 编辑:程序博客网 时间:2024/04/30 00:44

观察者模式的定义是:定义一个对象之间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象会自动被通知和更新。

Define a one-to-many dependency between objects so that one object changes state, all its dependents are notified and updated automatically.

在OO软件设计中,一个很重要的原则就是降低对象间的耦合关系并且要保证对象状态的一致性。

观察者模式中有两个角色,一个是subject,另一个observer,两者的关系就是一个subject对多个observer。当subject的状态发生变化时,需要通知observer。

他们之间的信息传递有两种方式,push和pull,push方式就是subject将变化的数据push给observer;pull方式就是subject用最少的信息告诉observer它需要更新了,obserer根据自己的数据需求来获取(get)subject的数据,

如果push和pull的关系比较复杂,可以引入一个专门负责控制变化的类--ChangeManager。因此就有了使用非常广泛的MVC模型,其实MVC模型至少用到了两个设计模式,一个就是观察者模型,而control类就是中介者模式(Mediator)。

以下代码是《Design Patterns》给出的sample:

定义了一个观察者的list,以及观察者subscribe和unsubscribe的Attach, Detach函数,还有就是发送通知的Notify函数。

这里没有把Subject定义成与java的interface等价的abstract class,因为C++支持多继承。

subject.h

#ifndef _HEADER_SUBJECT_#define _HEADER_SUBJECT_#include <list>using namespace std;class Observer;class Subject {public:    virtual ~Subject();    virtual void Attach(Observer*);    virtual void Detach(Observer*);    virtual void Notify();protected:    Subject();private:    list<Observer*> _observers;};#endif // _HEADER_SUBJECT_

subject.cpp

#include "subject.h"#include "observer.h"Subject::Subject() {}void Subject::Attach(Observer* o) {    _observers.push_front(o);}void Subject::Detach(Observer* o) {    _observers.remove(o);}void Subject::Notify() {    for (list<Observer*>::iterator it = _observers.begin(); it != _observers.end(); ++it) {        (*it)->Update(this);    }}Subject::~Subject() {    for (list<Observer*>::iterator it = _observers.begin(); it != _observers.end(); ++it) {        delete *it;    }}

Observer类比较简单,不过Observer是一个纯虚类,只定义了一个所有子类必须实现的Update函数。

observer.h

#ifndef _HEADER_OBSERVER_#define _HEADER_OBSERVER_class Subject;class Observer {public:    virtual ~Observer() { }    virtual void Update(Subject* theChangedSubject) = 0;protected:    Observer() { }};#endif // _HEADER_OBSERVER_

接下来就需要定义subject与observer的实例类了,本例使用了一个时钟类作为subject的子类。

clocktimer.h

#ifndef _HEADER_CLOCK_TIMER_#define _HEADER_CLOCK_TIMER_#include "subject.h"class ClockTimer : public Subject {public:    ClockTimer();    virtual int GetHour();    virtual int GetMinute();    virtual int GetSecond();    void Tick();private:    int _hour;    int _minute;    int _second;};#endif

clocktimer.cpp

#include "clocktimer.h"ClockTimer::ClockTimer() {}int ClockTimer::GetHour() {    return _hour;}int ClockTimer::GetMinute() {    return _minute;}int ClockTimer::GetSecond() {    return _second;}void ClockTimer::Tick() {    // update internal time-keeping state    // ...    _hour++;    _minute++;    _second++;    Notify();}

然后定义observer的实例类

digitalclock.h

#ifndef _HEADER_DIGITAL_CLOCK_#define _HEADER_DIGITAL_CLOCK_#include "widget.h"#include "observer.h"class ClockTimer;class DigitalClock : public Widget, public Observer {public:    DigitalClock(ClockTimer*);    virtual ~DigitalClock();    virtual void Update(Subject*);    virtual void Draw();private:    ClockTimer* _subject;};#endif


digitalclock.cpp
#include "digitalclock.h"#include "clocktimer.h"#include <iostream>DigitalClock::DigitalClock(ClockTimer* s)    : _subject(s) {    _subject->Attach(this);}DigitalClock::~DigitalClock() {    _subject->Detach(this);}void DigitalClock::Update(Subject* theChangedSubject) {    if (_subject == theChangedSubject) {        Draw();    }}void DigitalClock::Draw() {    int hour = _subject->GetHour();    int minute = _subject->GetMinute();    std::cout << "hour: " << hour << "\n" << "minute: " << minute << std::endl;}


main.cpp

#include "clocktimer.h"#include "digitalclock.h"int main(int argc, char** argv) {    ClockTimer* timer = new ClockTimer;    DigitalClock* digitalClock = new DigitalClock(timer);    timer->Tick();    timer->Tick();    timer->Tick();    return 0;}

widget.h

#ifndef _HEADER_WIDGET_#define _HEADER_WIDGET_class Widget {public:    virtual ~Widget() { }    virtual void Draw() = 0;protected:    Widget() { }};#endif

Java中已经提供了现成的Observer接口以及Observable抽象类来实现观察者模式。

不过因为java不能够多继承,因此Observable的设计有些瑕疵,具体看参加《Head First Design Patterns》观察者模式一章。

因为Observable是个类,那么继承自其他类的子类就无法复用Observable类了。

如果把Observable定义成接口,那么每次实现subject类的时候就需要重写注册,取消注册与发送通知的代码。

这个应该算是java不支持多继承的一个弊端吧? 


PS:快一年没怎么动C++,还真有点手生。。。