观察者模式(Observer)

First Post:

Last Update:

观察者模式(Observer)

发布-订阅模式(Publish/Subscribe)

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象状态发生改变时,会通知所有的观察者对象,使他们能够自动更新自己。所以也称之为发布-订阅模式(Publish/Subscribe)。

观察者模式结构图

观察者模式成员分析

Subject类,主题类,通常用一个抽象类或者抽象接口实现。他把所有对观察者对象的引用保存在一个聚集内。

observer类,观察者类,为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
ConcreteSubject,具体主题类,存入有关状态到具体观察者对象,在具体主题内部状态发生改变时,给所有登记的观察者发出通知.

ConcreteObserver,具体观察者,在得到主题的通知时更新自己。

观察者模式代码结构

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
//Subject类,主题类,通常用一个抽象类或者抽象接口实现。他把所有对观察者对象的引用保存在一个聚集内。
abstract class Subject
{
private Ilist<Observer> observers = new List<Observer>();
//增加观察者
public void Attach(Observer observer)
{
observer.Add(observer);
}
//移除观察者
public void Detach(Observer observer)
{
observer.Remove();
}
//通知
public void Notify( )
{
foreach(Observer o in observers)
{
o.Update();
}
}
}

//observer类,观察者类,为所有具体的观察者定义一个接口,在得到主题的通知时更新自己
abstract class observer()
{
public abstract void Update();
}

//具体主题类,存入有关状态到具体观察者对象,在具体主题内部状态发生改变时,给所有登记的观察者发出通知.
class ConCreteSubject : Subject
{
private string subjectState;//具体被观察者的状态
public string SubjectState
{
get{return subjectState;}
set{subjectState = value;}
}
}

//具体观察者
class ConcreteObserver :Observer
{
private string name;
private striing observerState;
private ConcreteSubject subject;
public ConcreteObserver(ConserverSubject subject,string name)
{
this.name = name;
this.subject = subject;
}
public override void Update()
{
observerState = subject.SubjectState;
//新状态是:
}
public ConcreteSubject Subject
{
get{return subjectState;}
set{subjectState = value;}
}
}

客户端代码
ConcreteSubject s = new ConcreteSubject();
s.Attach(new ConcreteObserver(s,"X"));
s.Attach(new ConcreteObserver(s,"Y"));
s.SubjectState = "newState";
s.Notify( );

观察者模式总结

观察者模式的核心思想是利用依赖倒置原则来解耦,通过抽象出主题类和观察者类两个类的抽象接口,来实现主题类一通知,观察者就随之改变状态。

用在哪里?

当将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是要维护相关对象的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、拓展和重用都带来不便。

关键对象——Subject和Observer

Subject对象不必知道具体哪个Observer,一旦发生改变,Subject将通知所有Observer。 Observer不必知道他自身具体的通知者,也不需要知道其他Observer的存在。

这样使得程序不再紧密耦合。

什么时候使用?

一般用于一个对象改变需要同时改变其他对象时,而且它不知道具体由多少个对象有待改变时,应该考虑使用观察者模式。

不足:

一个是,抽象的通知者还是依赖于抽象的观察者,如果没有这个抽象观察者接口,这个通知的接口功能就不能完成。

另一个是,对于每一个具体的观察者,不一定都是同样的“Update”方法的调用。

如果通知者和观察者之间根本就互相不知道,由客户端来决定通知谁,该如何实现?

C#观察者模式的委托实现

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
委托实现:
首先——两个观察者类Observer将Update更名为具体的方法Method1、Method2
第二——抽象通知者不希望依赖于抽象观察者,所有关于“增减”观察者的方法不被需要,删去。

interface Subject
{
void Notify();
string SubjectState{get;set;}
}

第三——为具体通知者声明委托
delegate void EventHandler();

class Notifier1 : Subject
{
public event EventHandler Update;
//声明一个"EventHandler(事件处理程序)"的委托事件,
//名称叫Update
private string action;

public void Notify()
{//在访问通知方法时,调用委托Update“更新”
Update( );
}

public string SubjectState
{
get{return action;}
set{action = value;}
}
}

class Notifier2 : Subject
{
//同上类似
}

客户端:
Notifier1 ner = new Notifier1( );
ConcreteObserver1 zxf = new ConcreteObserver1("zxf",ner);
ConcreteObserver1 hyx = new ConcreteObserver1("hyx",ner);

ner.Update +=new EventHandler(zxf.Method1);
ner.Update +=new EventHandler(hyx.Method2);
//将具体观察者类的方法挂在通知者的Update方法上,也就是将两类不同的方法委托给了通知者类的Update。

ner.SubjectState = "xxx";
ner.Notify( );

映射到游戏开发里面就是事件、广播等的实现