`
isiqi
  • 浏览: 16028363 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

认识观察者模式(设计模式)[转载]

阅读更多
认识观察者模式(设计模式)
-、开题
设计模式就好比天屠龙记里的兵法书武穆遗书哦,看了设计模式就会惊呼,软件设计中你已经在不知不觉使用,或者碰到了但尚未解决的,或者至今还没意识到的问题,上边都有了经验总结;学习了想必事半功倍,具体还要在实践中不断尝试。
设计模式一书已经被存储到大家知识库里并且逐步重视起来基础上,这次我们来认识和讨论一下观察者模式,
观察者模式:
这里不多说,空间留给大家,可以从观察者模式的背景、意图、适用范围、优点、缺点、最好结合例子谈谈。
二讨论
Charley Chen跟贴:
实现观察者模式有很多形式,比较直观的一种是使用一种注册——通知——撤销注册的形式。下面的三个图详细的描述了这样一种过程:
1:观察者(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。


2:被观察对象发生了某种变化(如图中的AskPriceChanged),从容器中得到所有注册过的观察者,将变化通知观察者。

此主题相关图片如下:

3:观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。

此主题相关图片如下:

观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。
(一)通过别名从不同角度来理解
发布-订阅(Publish/Subscribe)模式:状态变更的动作基本上是由被观察者发出,因此这个别名比观察者更加贴切
模型-视图(Model/View)模式:该模式重要的应用场合,也是最为适合的应用场合,常常作为示例
-监听器(Source/Listener)模式:?
从属者(Dependents)模式:?
(二)C#.NET中可以通过DelegateEvent机制简化Observer模式
详见下,对于.NET还不是很熟,例子摘录自C#设计模式
(三)Java中内建了类java.util.Observerable和接口java.util.Observer,是对Observer的简单实现
详见下,链了一篇介绍
四、C#中的DelegateEvent
实际上在C#中实现Observer模式没有这么辛苦,.NET中提供了DelegateEvent机制,我们可以利用这种机制简化Observer模式。关于DelegateEvent的使用方法请参考相关文档。改进后的Observer模式实现如下:
//Observerpattern--Structuralexample
usingSystem;

//Delegate
delegatevoidUpdateDelegate();

//Subject
classSubject
{
publiceventUpdateDelegateUpdateHandler;

//Methods
publicvoidAttach(UpdateDelegateud)
{
UpdateHandler+=ud;
}

publicvoidDetach(UpdateDelegateud)
{
UpdateHandler-=ud;
}

publicvoidNotify()
{
if(UpdateHandler!=null)UpdateHandler();
}

}

//ConcreteSubject
classConcreteSubject:Subject
{
//Fields
privatestringsubjectState;

//Properties
publicstringSubjectState
{
get{returnsubjectState;}
set{subjectState=value;}
}
}

//"ConcreteObserver"
classConcreteObserver
{
//Fields
privatestringname;
privatestringobserverState;
privateConcreteSubjectsubject;

//Constructors
publicConcreteObserver(ConcreteSubjectsubject,
stringname)
{
this.subject=subject;
this.name=name;
}

//Methods
publicvoidUpdate()
{
observerState=subject.SubjectState;
Console.WriteLine("Observer{0}'snewstateis{1}",
name,observerState);
}

//Properties
publicConcreteSubjectSubject
{
get{returnsubject;}
set{subject=value;}
}
}

//"ConcreteObserver"
classAnotherObserver
{
//Methods
publicvoidShow()
{
Console.WriteLine("AnotherObservergotanNotification!");
}
}

publicclassClient
{
publicstaticvoidMain(string[]args)
{
ConcreteSubjects=
newConcreteSubject();
ConcreteObservero1=
newConcreteObserver(s,"1");
ConcreteObservero2=
newConcreteObserver(s,"2");
AnotherObservero3=
newAnotherObserver();

s.Attach(
newUpdateDelegate(o1.Update));
s.Attach(
newUpdateDelegate(o2.Update));
s.Attach(
newUpdateDelegate(o3.Show));

s.SubjectState="ABC";
s.Notify();

Console.WriteLine("--------------------------");
s.Detach(
newUpdateDelegate(o1.Update));

s.SubjectState="DEF";
s.Notify();
}
}
其中,关键的代码如下:
delegatevoidUpdateDelegate();
定义一个Delegate,用来规范函数结构。不管是ConcreteObserver类的Update方法还是AnotherObserver类的Show方法都符合该Delegate。这不象用Observer接口来规范必须使用Update方法那么严格。只要符合Delegate所指定的方法结构的方法都可以在后面被事件所处理。
publiceventUpdateDelegateUpdateHandler;
定义一个事件,一旦触发,可以调用一组符合UpdateDelegate规范的方法。
publicvoidAttach(UpdateDelegateud)
{
UpdateHandler+=ud;
}
订阅事件。只要是一个满足UpdateDelegate的方法,就可以进行订阅操作(如下所示)。
s.Attach(newUpdateDelegate(o1.Update));
s.Attach(
newUpdateDelegate(o2.Update));
s.Attach(
newUpdateDelegate(o3.Show));
Notify方法中:
publicvoidNotify()
{
if(UpdateHandler!=null)UpdateHandler();
}
只要UpdateHandler != null(表示有订阅者),就可以触发事件(UpdateHandler()),所有的订阅者便会接到通知。
关于事件的使用,有一点还是值得注意:
一般我们认为:全部的事件处理器都应该返回void并接受两个参数:第一个参数为一个对象,它代表产生事件的对象;第二个参数是从System.EventArgs中派生而来的类的对象。EventArgs是事件数据的基类,并代表了事件的细节。
摘自范亮的举例:
ConcreteSubjects=newConcreteSubject();
ConcreteObservero1=newConcreteObserver(s,"1");
ConcreteObservero2=
newConcreteObserver(s,"2");
AnotherObservero3=
newAnotherObserver();

s.Attach(
newUpdateDelegate(o1.Update));
s.Attach(
newUpdateDelegate(o2.Update));
s.Attach(
newUpdateDelegate(o3.Show));
如果o1,o2,o3有统一的接口去响应主题的UpdateHandler事件,那就可以去实现(继承)同一接口IObserver,编程会变的更加简练,当然这是锦上天花的事,例子已经能够说明观察者模式的思想.

下面我就随便谈谈观察者模式背景、意图、适用范围、优点、缺点...
先谈背景:
还是举个列子
A

Class A
{
function funA()
{
}
}
B

Class B
{
function funB()
{

}
}
C

Class C
{
function funC()
{
A.funA();
B.funB();
}
}
如果观察者模式可以总结成下面的应用:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。(摘自新版设计模式手册[C#].pdf)
那上边的例子是否看成观察者模式的最原始的一种呢?
优点:
是实现了表示层和数据逻辑层的分离,并定义了稳定的更新消息传递机制,类别清晰,并抽象了更新接口,使得可以有各种各样不同的表示层
缺点:
如果1NN很大时,花销较大。
三:总结
观察者模式的讨论先告一段落,主要还要在实践中慢慢体会.
1.
在分层设计中,同层类的交互,就是横向调用比如在Bussiness层,如果有当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新的,我们可以尝试观察者模式,从而降低类之间的耦合性,我
写的例子是一种强耦合的,一定程度上讲破坏了类的高内聚低耦合及封闭原则.
2.C#
编程中Delegate-Event就是很好的观察者模式原形,我们要多用它.

以下摘自C#设计模式一书,讲的蛮好:
观察者模式的效果有以下几个优点:
1)观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体现察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
2)观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。
观察者模式有下面的一些缺点:
1)如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察考模式时要特别注意这一点。
3)如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
4)虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
此主题相关图片如下:
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics