行为型 - 观察者(Observer)

观察者模式(Observer): 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象,在它的状态发生变化时,会通知所有的观察者。

抛砖引玉

Observer 模式应该可以说是应用最多、影响最广的模式之一,因为 Observer 的一个实例 Model/View/Control( MVC) 结构在系统开发架构设计中有着很重要的地位和意义, MVC实现了业务逻辑和表示层的解耦。

Observer 模式要解决的问题为:建立一个一( Subject)对多( Observer) 的依赖关系, 并且做到当“一” 变化的时候, 依赖这个“一” 的多也能够同步改变。

最常见的一个例子就是:对同一组数据进行统计分析时候,希望能够提供多种形式的表示(例如以表格进行统计显示、 柱状图统计显示、 百分比统计显示等)。这些表示都依赖于同一组数据,当然需要当数据改变的时候,所有的统计的显示都能够同时改变。Observer 模式就是解决了这一个问题。

Observer 模式典型的结构图为:

具体思路解析:

  1. Subject 提供依赖于它的观察者 Observer 的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。

  2. Subject通过维护list<Observer* >* _obvs,Object维护Subject* _sub,使用时。先创建Subject* sub,然后将其作为变量传递给Observer* o1,o2,使得ConcreteObserver在构造时完成Attach操作,将监听对象加入Subject的监听队列_obvs。

  3. Subject* sub 通过SetState函数改变状态,在调用Notify去遍历监听队列_obvs,更新Observer* o1,o2的状态。

代码实现

#ifndef _SUBJECT_H_
#define _SUBJECT_H_
#include <list>
#include <string>

using namespace std;
typedef string State;

class Observer;

class Subject
{
public:
	virtual ~Subject();
	virtual void Attach(Observer *obv);
	virtual void Detach(Observer *obv);
	virtual void Notify();
	virtual void SetState(const State &st) = 0;
	virtual State GetState() = 0;

protected:
	Subject();

private:
	list<Observer *> *_obvs;
};

class ConcreteSubject : public Subject
{
public:
	ConcreteSubject();
	~ConcreteSubject();
	State GetState();
	void SetState(const State &st);

protected:
private:
	State _st;
};
#endif //~_SUBJECT_H_
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "Subject.h"
#include "Observer.h"
#include <iostream>
#include <list>
using namespace std;
typedef string state;

Subject::Subject()
{ //在模板的使用之前一定要 new,创建
	_obvs = new list<Observer *>;
}

Subject::~Subject()
{
}

void Subject::Attach(Observer *obv)
{
	_obvs->push_front(obv);
}

void Subject::Detach(Observer *obv)
{
	if (obv != NULL)
	{
		_obvs->remove(obv);
	}
}

void Subject::Notify()
{
	list<Observer *>::iterator it;
	it = _obvs->begin();
	for (; it != _obvs->end(); it++)
	{ //关于模板和 iterator 的用法
		(*it)->Update(this);
	}
}

ConcreteSubject::ConcreteSubject() //会隐式调用基类的默认构造函数
{
	_st = '\0';
}

ConcreteSubject::~ConcreteSubject()
{
}

State ConcreteSubject::GetState()
{
	return _st;
}

void ConcreteSubject::SetState(const State &st)
{
	_st = st;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#ifndef _OBSERVER_H_
#define _OBSERVER_H_

#include "Subject.h"
#include <string>

using namespace std;
typedef string State;

class Observer
{
public:
	virtual ~Observer();
	virtual void Update(Subject *sub) = 0;
	virtual void PrintInfo() = 0;

protected:
	Observer();
	State _st;

private:
};

class ConcreteObserverA : public Observer
{
public:
	virtual Subject *GetSubject();
	ConcreteObserverA(Subject *sub);
	virtual ~ConcreteObserverA();
	//传入 Subject 作为参数,这样可以让一个View 属于多个的 Subject。
	void Update(Subject *sub);
	void PrintInfo();

protected:
private:
	Subject *_sub;
};

class ConcreteObserverB : public Observer
{
public:
	virtual Subject *GetSubject();
	ConcreteObserverB(Subject *sub);
	virtual ~ConcreteObserverB();
	//传入 Subject 作为参数,这样可以让一个View 属于多个的 Subject。
	void Update(Subject *sub);
	void PrintInfo();

protected:
private:
	Subject *_sub;
};
#endif //~_OBSERVER_H_
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include "Observer.h"
#include "Subject.h"
#include <iostream>
#include <string>

using namespace std;

Observer::Observer()
{
	_st = '\0';
}

Observer::~Observer()
{
}

ConcreteObserverA::ConcreteObserverA(Subject *sub)
{
	_sub = sub;
	_sub->Attach(this);
}

ConcreteObserverA::~ConcreteObserverA()
{
	_sub->Detach(this);
	if (_sub != 0)
		delete _sub;
}

Subject *ConcreteObserverA::GetSubject()
{
	return _sub;
}

void ConcreteObserverA::PrintInfo()
{
	cout << "ConcreteObserverA observer...." << _sub->GetState() << endl;
}

void ConcreteObserverA::Update(Subject *sub)
{
	_st = sub->GetState();
	PrintInfo();
}

ConcreteObserverB::ConcreteObserverB(Subject *sub)
{
	_sub = sub;
	_sub->Attach(this);
}

ConcreteObserverB::~ConcreteObserverB()
{
	_sub->Detach(this);
	if (_sub != 0)
	{
		delete _sub;
	}
}

Subject *ConcreteObserverB::GetSubject()
{
	return _sub;
}

void ConcreteObserverB::PrintInfo()
{
	cout << "ConcreteObserverB observer...." << _sub->GetState() << endl;
}

void ConcreteObserverB::Update(Subject *sub)
{
	_st = sub->GetState();
	PrintInfo();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include "Subject.h"
#include "Observer.h"
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
	Subject *sub = new ConcreteSubject();
	Observer *o1 = new ConcreteObserverA(sub);
	Observer *o2 = new ConcreteObserverB(sub);

	sub->SetState("old");
	sub->Notify();
	sub->SetState("new"); // 也可以由Observer 调用
	sub->Notify();

	return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

执行结果如下,因为list是头插法,后加入的ConcreteObserverB在sub广播通知list的开头,所以通知的消息先到达B:

[root@192 base_use]# ./ObserverTest
ConcreteObserverB observer....old
ConcreteObserverA observer....old
ConcreteObserverB observer....new
ConcreteObserverA observer....new
1
2
3
4
5

代码说明

在 Observer 模式的实现中:

  1. Subject 维护一个 list 作为存储其所有观察者的容器。每当调用 Notify 操作就遍历 list 中的 Observer 对象, 并广播通知改变状态(调用 Observer 的 Update操作)。

  2. 目标的状态 state 可以由 Subject 自己改变( 示例),也可以由 Observer 的某个操作引起 state 的改变(可调用 Subject 的 SetState 操作。

  3. Notify 操作可以由 Subject 目标主动广播(示例),也可以由 Observer 观察者来调用(因为 Observer 维护一个指向 Subject 的指针)。

  4. 运行示例程序,可以看到当 Subject 处于状态“ old” 时候, 依赖于它的两个观察者都显示“ old”,当目标状态改变为“ new”的时候,依赖于它的两个观察者也都改变为“ new”。

讨论

Observer 是影响极为深远的模式之一,也是在大型系统开发过程中要用到的模式之一。除了 MFC、 Struts 提供了 MVC 的实现框架, 在 Java 语言中还提供了专门的接口实现 Observer模式:通过专门的类 Observable 及 Observer 接口来实现 MVC 编程模式, 其 UML 图可以表示为

这里的 Observer 就是观察者, Observable 则充当目标 Subject 的角色。Observer 模式也称为发布-订阅( publish-subscribe),目标就是通知的发布者,观察者则是通知的订阅者(接受通知)。 ​