Csharp/C#教程:深入了解C#设计模式之订阅发布模式分享

什么是Pub-Sub

发布订阅是一种设计模式,它允许应用程序组件之间进行松散耦合。
其实订阅发布设计中主要是发布者生成事件通道,用于在不了解任何订阅者存在的情况下通知订阅者。

当然委托EventHandlers和Event关键字在此事件处理机制中担任着重要的角色。下面我们来看看如何使用它们。

Pub和Sub的使用

首先我们看一个简单地订阅发布模式.

定义一个Action委托,无返回值.

namespacePubSubPattern { publicclassPub { publicActionOnChange{get;set;} publicvoidRaise() { if(OnChange!=null) { //InvokeOnChangeAction OnChange(); } } } classProgram { staticvoidMain(string[]args) { varp=newPub(); p.OnChange+=()=>Console.WriteLine("Sub1"); p.OnChange+=()=>Console.WriteLine("Sub2"); p.Raise(); Console.WriteLine("Pressenter!"); Console.ReadLine(); } } }

如上代码我们创建了一个发布者,并且我们调用委托进行创建我们匿名方法来订阅。由于委托提供了多播功能,因此我们可以OnChange属性上使用+=.

虽然说我们看着如上代码执行无误,但是程序中仍然存在一些问题,如果使用=而不是+=,那么OnChange属性中将会删除第一个订阅者。
由于OnChange是公共属性,因此该类的任何外部用户都可以进行调用p.OnChange().

使用Event关键字的发布订阅

下面我们来看看使用event关键字后的代码

publicclassPub { publiceventActionOnChange=delegate{}; publicvoidRaise() { OnChange(); } } classProgram { staticvoidMain(string[]args) { Pubp=newPub(); p.OnChange+=()=>Console.WriteLine("Sub1"); p.OnChange+=()=>Console.WriteLine("Sub2"); p.Raise(); Console.WriteLine("Pressenter!"); Console.ReadLine(); } }

通过如上代码我们试着去解决我们第一处所说的问题,我们会发现使用event关键字后可以保护我们OnChange免受不必要的访问。它不允许使用=也就是说他不允许直接进行分配委托,因此我们现在可以避免使用=,从而避免应用程序不必要的麻烦。

可能大家也会发现OnChange初始化为空委托delegate{}。这样可以确保我们的OnChange永远不会为空。因为当我们其他进行对他调用的时候我们可以在代码中进行删除对他的非空检查.

使用EventHandlers的发布订阅

其实在订阅发布中,发布者和订阅者都不知道彼此的存在。有个EventHandler,它被称为消息代理或者说事件总线,发布者和订阅者都应该知道它,它接收所有传入的消息并且将它们进行转发.

因此呢,在如下片段中我们使用EventHandler而不是用Action.

publicdelegatevoidEventHandler( objectsender, EventArgse )

默认情况下,EventHandler将发送对象和一些事件参数作为参数。

publicclassMyEventArgs:EventArgs { publicintValue{get;set;} publicMyEventArgs(intvalue) { Value=value; } } publicclassPub { publiceventEventHandler<MyEventArgs>OnChange=delegate{}; publicvoidRaise() { OnChange(this,newMyEventArgs(1)); } } classProgram { staticvoidMain(string[]args) { Pubp=newPub(); p.OnChange+=(sender,e)=>Console.WriteLine("Sub1.Value:"+e.Value); p.OnChange+=(sender,e)=>Console.WriteLine("Sub2.Value:"+e.Value); p.Raise(); Console.WriteLine("Pressenter!"); Console.ReadLine(); } }

如上代码中通过pub类使用通用的EventHandler,它触发EventHandlerOnChange时需要传递的事件参数类型,在上面代码片段中为MyArgs

事件中的异常

我们继续说一种情况.大家看如下代码片段

publicclassMyEventArgs:EventArgs { publicintValue{get;set;} publicMyEventArgs(intvalue) { Value=value; } } publicclassPub { publiceventEventHandler<MyEventArgs>OnChange=delegate{}; publicvoidRaise() { OnChange(this,newMyEventArgs(1)); } } classProgram { staticvoidMain(string[]args) { Pubp=newPub(); p.OnChange+=(sender,e)=>Console.WriteLine("Sub1.Value:"+e.Value); p.OnChange+=(sender,e)=>{thrownewException();}; p.OnChange+=(sender,e)=>Console.WriteLine("Sub2.Value:"+e.Value); p.Raise(); Console.WriteLine("Pressenter!"); Console.ReadLine(); } }

运行如上代码后,大家会发现第一个订阅者已经执行成功了,第二个订阅者引发了异常,而第三个订阅者未被调用.这是一个很尴尬的事情.

如果说我们觉得如上的过程不是我们预期的,我们需要手动引发事件并处理异常,这时候我们可以使用Delegate基类中定义的GetInvoctionList来帮助我们实现这些。

我们继续看如下代码

publicclassMyEventArgs:EventArgs { publicintValue{get;set;} publicMyEventArgs(intvalue) { Value=value; } } publicclassPub { publiceventEventHandler<MyEventArgs>OnChange=delegate{}; publicvoidRaise() { MyEventArgseventArgs=newMyEventArgs(1); List<Exception>exceptions=newList<Exception>(); foreach(DelegatehandlerinOnChange.GetInvocationList()) { try { handler.DynamicInvoke(this,eventArgs); } catch(Exceptione) { exceptions.Add(e); } } if(exceptions.Any()) { thrownewAggregateException(exceptions); } } } classProgram { staticvoidMain(string[]args) { Pubp=newPub(); p.OnChange+=(sender,e)=>Console.WriteLine("Sub1.Value:"+e.Value); p.OnChange+=(sender,e)=>{thrownewException();}; p.OnChange+=(sender,e)=>Console.WriteLine("Sub2.Value:"+e.Value); p.Raise(); Console.WriteLine("Pressenter!"); Console.ReadLine(); } }

Reference

https://github.com/hueifeng/DesignPatterns-Samples/tree/master/PubSubPattern

https://hackernoon.com/observer-vs-pub-sub-pattern-50d3b27f838c

上述就是C#学习教程:深入了解C#设计模式之订阅发布模式分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/903796.html

(0)
上一篇 2021年10月21日
下一篇 2021年10月21日

精彩推荐