浅析C#之——Observer, Delegate和event(1)
这些天除了项目之外花时间最多的就是在研究C#里的Delegate和event......
此外,还在写文章的时候无意中研究了一下Observer设计模式...
其实说研究也惭愧,浅尝辄止而已,但还是想把学到的写出来分享一下,第一次写这类文章,面向广大的和我一样的低阶菜鸟级程序猿,还望大师们海涵加指点………………
关键词:
字段:通常指类对象中的成员变量,一般为私有。
属性:C#中较为独特的一种……签名?不知该怎么称呼,就是对字段(私有)添加了get和set方法后,可以像共有变量那样去调用。一般将变量名设置为大写。
方法:通常指类对象中的成员函数。
PS:感觉……所谓的字段、属性、方法等都是在面向对象编程中以对象的视角来看待变量和函数后所产生的称呼;
先来说一下Observer设计模式,其实这个不属于C#独有。它是一个设计模式,其实也是这三者中最重要的一个概念。
观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其它的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作(Collaboration)。观察者模式是满足这一要求的各种设计方案中最重要的一种。
概念定义啥的网上都能查得到,抽象的概念我就不多说了。接下来想用一组实例来说明这个设计模式。
假设现在有两个对象,分别为消息中心(MessageCenter)和消息库(MessageStore)。现在有一个机制是,消息中心每产生一条新信息,就要在消息库中备份;
先看一个没有运用设计模式的例子:noObserver.cs
using System; class MessageCenter { private String messageString; // MessageCenter用来缓存消息的String字段; // 新建消息; public void newMessage(String message) { Console.WriteLine("New message: " + message + "... [MessageCenter]" ); this.messageString = message; } // 通知MessageStore有新消息,将其备份入MessageStore; public void notice(MessageStore messageStore) { //messageStore.MessageString = this.messageString; //Console.WriteLine("Message: '" + messageString + "' have been stored in MessageStore..."); messageStore.storeMessage(this.messageString); } } class MessageStore { private String messageString; // MessageStore用户存储消息的String字段; // 其实应该是一个String容器用来存储多条消息,不过在此为了简单只放一条消息; public String MessageString { get{return messageString;} set{this.messageString = value;} } public void storeMessage(String message) { this.messageString = message; Console.WriteLine("Message: '" + this.messageString + "' have been stored in MessageStore..."); } // 列出MessageStore中已存储的消息; public void listMessages() { Console.WriteLine("Stored message1: '" + this.messageString + "'...[MessageStore]"); } } class Test { public static void Main() { MessageCenter messageCenter = new MessageCenter(); MessageStore messageStore = new MessageStore(); messageCenter.newMessage("Hello world!"); //新建消息Hello world; messageCenter.notice(messageStore); //通知messageStore有消息需要存储; messageStore.listMessages(); //列出messageStore中已经存储的消息; } }输出结果:
以上这个例子基本实现了消息中心向消息库存储消息的机制。不过其中有一个很大的问题是:
存储消息的方法被直接写在了MessageCenter的notice()方法体中,这使得消息库无法自己决定存储的方式;
我们可以做一些改进,就是将存储消息的方式写成一个属于MessageStore的方法,随后在MessageCenter的notice()方法中直接调用messageStore.storeMessage()方法:
class MessageCenter { ... // 通知MessageStore有新消息,将其备份入MessageStore; public void notice(MessageStore messageStore) { //messageStore.MessageString = this.messageString; //Console.WriteLine("Message: '" + messageString + "' have been stored in MessageStore..."); messageStore.storeMessage(this.messageString); } ... } class MessageStore { ... public void storeMessage(String message) { this.messageString = message; Console.WriteLine("Message: '" + this.messageString + "' have been stored in MessageStore..."); } ... }
但这样也有一个问题,就是MessageCenter在写notice方法的时候必须事先知道MessageStore中的存储消息的方法名,否则便无法调用,但倘若写MessageCenter和写MessageStore的程序猿不是同一个人,就需要很麻烦的事先确定好方法的命名。那如何避免这个麻烦的问题呢?
一个解决问题的方法是,让MessageCenter作者提供一个供MessageStore对象继承的抽象类或接口,并在其中定义一个名为storeMessage的虚方法,这样的话,MessageStore就只需要继承这个抽象类或接口并重写storeMessage()方法以实现自己想要的存储方法,而MessageCenter也可以在不知道存储方法的情况下在notice()方法中调用MessageStore的storeMessage()方法,从而实现解耦;
代码如下(其实只要修改很少的部分):tryObserver.cs
using System; interface ReceiveMessage { void storeMessage(String message); } class MessageCenter { private String messageString; // MessageCenter用来缓存消息的String字段; // 新建消息; public void newMessage(String message) { Console.WriteLine("New message: " + message + "... [MessageCenter]" ); this.messageString = message; } // 通知MessageStore有新消息,将其备份入MessageStore; //public void notice(MessageStore messageStore) public void notice(ReceiveMessage messageStore) //将对象参数类型换成接口类型; { //messageStore.MessageString = this.messageString; //Console.WriteLine("Message: '" + messageString + "' have been stored in MessageStore..."); messageStore.storeMessage(this.messageString); } } class MessageStore : ReceiveMessage { private String messageString; // MessageStore用户存储消息的String字段; // 其实应该是一个String容器用来存储多条消息,不过在此为了简单只放一条消息; public String MessageString { get{return messageString;} set{this.messageString = value;} } /* public void storeMessage(String message) { this.messageString = message; Console.WriteLine("Message: '" + this.messageString + "' have been stored in MessageStore..."); } */ public void storeMessage(String message) //实现接口方法storeMessage(String message); { this.messageString = message; Console.WriteLine("Message: '" + this.messageString + "' have been stored in MessageStore..."); } // 列出MessageStore中已存储的消息; public void listMessages() { Console.WriteLine("Stored message1: '" + this.messageString + "'...[MessageStore]"); } } class Test { public static void Main() { MessageCenter messageCenter = new MessageCenter(); MessageStore messageStore = new MessageStore(); messageCenter.newMessage("Hello world!"); //新建消息Hello world; messageCenter.notice(messageStore); //通知messageStore有消息需要存储; messageStore.listMessages(); //列出messageStore中已经存储的消息; } }
输出结果:
结果没变。以上代码基本实现了MessageCenter与MessageStore之间的一对一关联,耦合度也较松。
但这样还是不够灵活,如果想与MessageCenter关联的对象不只MessageStore一个,且希望能实现动态关联,即想关联的时候关联,不想关联的时候就可以断开,那就需要对代码做进一步修改。在此,我们可以再添加一个将与MessageCenter关联的MessageChecker对象,并在MessageCenter中设置一个ArrayList用来存储所有继承了ReceiveMessage接口的消息接收者(观察者Observer),并构造两个对其进行操作的addReceiver()方法和removeReceiver()方法,用来添加和移除receiver(观察者Observer);随后,修改notice方法,使其遍历ArrayList并调用每个receiver的storeMessage()方法。
代码如下:Observer.cs
using System; using System.Collections; interface ReceiveMessage { void storeMessage(String message); } class MessageCenter { private String messageString; // MessageCenter用来缓存消息的String字段; private ArrayList receiverList = new ArrayList(); //添加消息接受者; public void addReceiver(ReceiveMessage receiver) { receiverList.Add(receiver); } //移除消息接受者; public void removeReceiver(ReceiveMessage receiver) { receiverList.Remove(receiver); } // 新建消息; public void newMessage(String message) { Console.WriteLine("New message: " + message + "... [MessageCenter]" ); this.messageString = message; } // 通知MessageStore有新消息,将其备份入MessageStore; //public void notice(MessageStore messageStore) /* public void notice(ReceiveMessage messageStore) //将对象参数类型换成接口类型; { //messageStore.MessageString = this.messageString; //Console.WriteLine("Message: '" + messageString + "' have been stored in MessageStore..."); messageStore.storeMessage(this.messageString); } */ public void notice() //// 通知所有已注册的receiver有新消息,并调用其storeMessage方法; { foreach(Object receiver in receiverList) { (receiver as ReceiveMessage).storeMessage(this.messageString); } } } class MessageStore : ReceiveMessage { private String messageString; // MessageStore用户存储消息的String字段; // 其实应该是一个String容器用来存储多条消息,不过在此为了简单只放一条消息; public String MessageString { get{return messageString;} set{this.messageString = value;} } /* public void storeMessage(String message) { this.messageString = message; Console.WriteLine("Message: '" + this.messageString + "' have been stored in MessageStore..."); } */ public void storeMessage(String message) //实现接口方法storeMessage(String message); { this.messageString = message; Console.WriteLine("Message: '" + this.messageString + "' have been stored in MessageStore..."); } // 列出MessageStore中已存储的消息; public void listMessages() { Console.WriteLine("Stored message1: '" + this.messageString + "'...[MessageStore]"); } } class MessageChecker : ReceiveMessage { private String checkResult; public void storeMessage(String message) //实现接口方法storeMessage(String message); { this.checkResult = "OK!"; Console.WriteLine("The message: '" + message + "' has been checked..."); } public void showCheckResult() { Console.WriteLine("The checkResule is: " + this.checkResult + " [MEssageChecker]"); } } class Test { public static void Main() { MessageCenter messageCenter = new MessageCenter(); MessageStore messageStore = new MessageStore(); MessageChecker messageChecker = new MessageChecker(); messageCenter.addReceiver(messageStore); messageCenter.addReceiver(messageChecker); messageCenter.newMessage("Hello world!"); //新建消息Hello world; //messageCenter.notice(messageStore); //通知messageStore有消息需要存储; messageCenter.notice(); messageStore.listMessages(); //列出messageStore中已经存储的消息; messageChecker.showCheckResult(); //显示messageChecker的checkResule; } }
输出结果:
以上,就是著名的Observer设计模式的基本实现。
其中的各个继承了ReceiveMessage的对象receiver就对应了设计模式中的Observer观察者,而MessageCenter就是被观察者。被观察中中有一个用来记录观察者信息的表ArrayList receiverList,并在发生相应动作的时候调用notice方法通知所有已注册过的观察者,从而实现一对多的发布-订阅机制。
==================================================================================