使用范型观察者模式观察多个数据的实现
观察者模式是最灵活、最多变的一种模式。在现实开发中,我常常会遇到观察者很多而且观察的数据也各不相同的情况,如果采用经典的观察者实现方法,在观察者的Update方法中难免要传递Subject中自己并不关心的数据,为此我采用了另外一种实现方式,希望和各位共同探讨。
范型观察者接口
1
interface IObserver<DT> {
2
/// <summary>
3
/// 观察和监视的数据
4
/// </summary>
5
DT ObserverSubject { get;set;}
6![](/Images/OutliningIndicators/InBlock.gif)
7
/// <summary>
8
/// 响应
9
/// </summary>
10
void Respond();
11
}
其中ObserverSubject是所要关心的数据,实现这个接口的具体类,必须指明它所关系的数据对象。![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
2
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
3
![](/Images/OutliningIndicators/InBlock.gif)
4
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
5
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
6
![](/Images/OutliningIndicators/InBlock.gif)
7
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
8
![](/Images/OutliningIndicators/InBlock.gif)
9
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
10
![](/Images/OutliningIndicators/InBlock.gif)
11
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
例如:
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
其中UIData对象是存储界面数据的,UI观察者所关心的数据也就是UIData类型,如果给它Log类型的数据就是浪费。
下面来关注一下Subject,因为这里面观察的数据是多种多样的,就是把关心的数据放在一起还是分散开来呢?哪一种更有利于扩展呢?这个问题我也曾经苦恼过,最后决定把所关心的数据分离开来,并使用委托的方式来实现通知观察者。
1
public delegate void RespondHandler();
2
class SubjectUI {
3
public event RespondHandler OnRespond;
4![](/Images/OutliningIndicators/InBlock.gif)
5
private UIData _uiData = new UIData();
6![](/Images/OutliningIndicators/InBlock.gif)
7
public UIData UIdata {
8
get { return _uiData; }
9
set { _uiData = value; }
10
}
11![](/Images/OutliningIndicators/InBlock.gif)
12
public void Notify() {
13
if (OnRespond != null) {
14
OnRespond();
15
}
16
}
17![](/Images/OutliningIndicators/InBlock.gif)
18
}
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
3
![](/Images/OutliningIndicators/InBlock.gif)
4
![](/Images/OutliningIndicators/InBlock.gif)
5
![](/Images/OutliningIndicators/InBlock.gif)
6
![](/Images/OutliningIndicators/InBlock.gif)
7
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
8
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
9
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
10
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
11
![](/Images/OutliningIndicators/InBlock.gif)
12
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
13
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
14
![](/Images/OutliningIndicators/InBlock.gif)
15
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
16
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
17
![](/Images/OutliningIndicators/InBlock.gif)
18
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
从上面的代码中不难看出定义了一个OnRespond事件,使用了委托RespondHandler.在通知Notify方法中,他会激发注册事件。它本身不需要关心谁会被激发,从而表现的比较独立和灵活。
应用的时候,
1
uiObserver.ObserverSubject.Value = 100;
2
subUI.Notify();
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/None.gif)
注意上面两行代码UI观察者观察的数据被改动了,观察着的经典模式是通过事件参数或者是访问Subject中包含的数据。但是如果使用事件参数,导致如果增加一种观察的类型,事件参数就会变得很庞大,另外我曾经考虑过通过访问Subject中包含的类型作为通知的数据,但是自我感觉更习惯于从观察者自身所关心的数据进行修改,然后通知被观察的数据。
由于本人刚刚接触设计模式没多久,可能很多地方考虑不妥,还请各位指点,共同切磋。