分享
 
 
 

设计模式:利用C#的Delegate来改进Observer模式

王朝c#·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Observer模式是我们应用得非常多的一个模式,因为它定义了单数据源多视图结构的消息传递基本机制和对象设计,所以在几乎所有的将表示层与数据逻辑层分开的多层应用软件上都能套用上Observer模式。本文将分析C#语言来实现该模式的代码,并且针对该模式存在的一些缺点,利用C#的一个新特性Delegate来尝试对该模式进行了一些改进。

为了让更多的人能够看明白本文,所以在此之前,我们先来了解一下Observer模式的基本概念。

模式名称:Observer

结构图:

意图:

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

适用性:

当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。

当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。

应用实例:

在编写多层应用程序时,我们通常将表示层和数据逻辑层分隔开,比如很常见的View/Document结构,这种设计方式的好处带来的结果通常是使用多视图同时表示单一数据源,比如一个Web网站可以方便的同时拥有针对电脑的Html页面和针对手机的WAP页面。使用这种结构时,为了保持数据显示的一致性,必须要求数据源在数据发生改变时能及时的逐一通知每一个和它绑定的表示层进行更新。但是问题在于数据层本身并不知道到底有多少个不同的表示层正在反映着它的数据内容。因此需要设计一套有效的机制来完成这个目标。

模式实现:

我们先看看来自《设计模式迷你手册》的常规的C#实现代码。

Subject(抽象目标):

目标知道它的观察者。可以有任意多个观察者观察同一个目标。

//实现代码

class Subject

{

//由于不知道有多少个观察者,所以建立了一个观察者链表

private ArrayList list = new ArrayList();

private string strImportantSubjectData = "Initial";

public string ImportantSubjectData

{

get

{

return strImportantSubjectData;

}

set

{

strImportantSubjectData = value;

}

}

public void Attach(Observer o)

{

list.Add(o);

o.ObservedSubject = this;

}

public void Detach(Observer o)

{

}

public void Notify()

{

//在数据发生改变后遍历列表通知观察者

foreach (Observer o in list)

{

o.Update();

}

}

}

Observer(抽象观察者):

为那些在目标发生改变时需要获得通知的对象定义一个更新接口。

abstract class Observer

{

//内置一个需要观察的对象

protected Subject s;

public Subject ObservedSubject

{

get

{

return s;

}

set

{

s = value;

}

}

abstract public void Update();

}

ConcreteSubject(实体目标,在这里相当于数据逻辑层):

将有关状态存入各ConcreteSubject对象。

当它的状态发生改变时,向它的各个观察者发出通知。

//在这里基本上什么都没有做,数据的获取可以放到GetState()里面

class ConcreteSubject : Subject

{

public void GetState()

{

}

public void SetState()

{

}

}

ConcreteObserver(实体观察者,在这里就相当于表示层):

维护一个指向ConcreteSubject的引用。

储存有关状态,这些状态应与目标的状态保持一致。

实现Observer的更新接口以使自身状态与目标状态保持一致。

class ConcreteObserver : Observer

{

private string observerName;

public ConcreteObserver(string name)

{

observerName = name;

}

override public void Update()

{

//将数据显示出来

Console.WriteLine("In Observer {0}: data from subject = {1}",

observerName, s.ImportantSubjectData);

}

}

主函数:

public class Client

{

public static int Main(string[] args)

{

ConcreteSubject s = new ConcreteSubject();

ConcreteObserver o1 = new ConcreteObserver("first observer");

ConcreteObserver o2 = new ConcreteObserver("second observer");

//注册观察者

s.Attach(o1);

s.Attach(o2);

s. ImportantSubjectData = "This is important subject data";

s.Notify();

return 0;

}

}

模式分析:

Observer模式的优点是实现了表示层和数据逻辑层的分离,并定义了稳定的更新消息传递机制,类别清晰,并抽象了更新接口,使得可以有各种各样不同的表示层(观察者)。但是其缺点是每个外观对象必须继承这个抽像出来的接口类,这样就造成了一些不方便,比如有一个别人写的外观对象,并没有继承该抽象类,或者接口不对,我们又希望不修改该类直接使用它。虽然可以再应用Adapter模式来一定程度上解决这个问题,但是会造成更加复杂烦琐的设计,增加出错几率。

C#作为一种先进的现代面向对象语言,不但吸收了许多语言的精华,并创造了一些非常有用的新特性。在学习了C#语言之后,我发现利用C#独有的Delegate可以来较好的解决这个问题。

改进后的Observer模式实现:

先定义一个Delegate:

delegate void UpdateDelegate(string SubjectData);

Subject(抽象目标):

class Subject

{

private string strImportantSubjectData = "Initial";

//定义一个事件容器,代替前面的观察者对象列表

public event UpdateDelegate UpdateHandle;

public string ImportantSubjectData

{

get

{

return strImportantSubjectData;

}

set

{

strImportantSubjectData = value;

}

}

public void Notify()

{

//发出事件

if(UpdateHandle != null) UpdateHandle(strImportantSubjectData);

}

}

Observer(抽象观察者):无,因为不需要抽象接口类了,所以可以省去抽象观察者类。

ConcreteSubject(实体目标):

//没有任何改变

class ConcreteSubject : Subject

{

public void GetState()

{

}

public void SetState()

{

}

}

ConcreteObserver(实体观察者):

//为了能更加清楚的说明问题,这里定义了两个实体观察者,注意,它们之间并没有任何关系

class Observer1

{

private string observerName;

public Observer1(string name)

{

observerName = name;

}

public void Update1(string ImportantSubjectData)

{

Console.WriteLine("In Observer {0}: data from subject = {1}",

observerName, ImportantSubjectData);

}

}

class Observer2

{

private string observerName;

public Observer2(string name)

{

observerName = name;

}

public void Update2(string ImportantSubjectData)

{

Console.WriteLine("In Observer {0}: data from subject = {1}",

observerName, ImportantSubjectData);

}

}

主函数:

public class Client

{

public static int Main(string[] args)

{

ConcreteSubject s = new ConcreteSubject();

Observer1 o1 = new Observer1("first observer");

Observer2 o2 = new Observer2("second observer");

//向目标注册对象两个观察者,请注意,这里仅仅只是添加了两个方法,不需要关心方法从何而来,也不需要关心目标类如何去调用他们。

s.UpdateHandle += new UpdateDelegate(o1.Update1);

s.UpdateHandle += new UpdateDelegate(o2.Update2);

s.ImportantSubjectData = "This is important subject data";

s.Notify();

return 0;

}

}

在这段代码里,没有看到链表,没有看到遍历操作,没有看到更新的方法是如何被调用,甚至没有看到那些被联系到一起的类的抽象类和抽象接口,但是目标对象却能将数据更新信息逐一发送到每个观察者对象,并且还能更加容易的增加新的不同的观察者对象,根本不需要知道它从何处继承而来,也不需要统一他们的接口调用方法。这一切都归功于灵活强大的C#。

以下是完整的源码:

namespace Observer_DesignPattern

{

using System;

delegate void UpdateDelegate(string SubjectData);

class Subject

{

private string strImportantSubjectData = "Initial";

public event UpdateDelegate UpdateHandle;

public string ImportantSubjectData

{

get

{

return strImportantSubjectData;

}

set

{

strImportantSubjectData = value;

}

}

public void Notify()

{

if(UpdateHandle != null) UpdateHandle(strImportantSubjectData);

}

}

class ConcreteSubject : Subject

{

public void GetState()

{

}

public void SetState()

{

}

}

class Observer1

{

private string observerName;

public Observer1(string name)

{

observerName = name;

}

public void Update1(string ImportantSubjectData)

{

Console.WriteLine("In Observer {0}: data from subject = {1}",

observerName, ImportantSubjectData);

}

}

class Observer2

{

private string observerName;

public Observer2(string name)

{

observerName = name;

}

public void Update2(string ImportantSubjectData)

{

Console.WriteLine("In Observer {0}: data from subject = {1}",

observerName, ImportantSubjectData);

}

}

public class Client

{

public static int Main(string[] args)

{

ConcreteSubject s = new ConcreteSubject();

Observer1 o1 = new Observer1("first observer");

Observer2 o2 = new Observer2("second observer");

s.UpdateHandle += new UpdateDelegate(o1.Update1);

s.UpdateHandle += new UpdateDelegate(o2.Update2);

s.ImportantSubjectData = "This is important subject data";

s.Notify();

return 0;

}

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有