俗语中,笑话一个地方穷,就经常说“通讯基本靠吼,交通基本靠走”。无独有偶,今天我们也要介绍一个类似于通讯基本靠吼的事件处理方式——EventAggregator。
首先回想一下,我们怎么完成事件处理?简单的三步。
非常简单的结构,如下所示。订阅者依赖于主体。
如果一个主体有多个订阅者,那么多个订阅者将会依赖于同一个主体。
如果情况再变化一下,多个主体有多个订阅者,那么依赖就会更加复杂。
看到这里,相信大家已经明白了,这种传统的事件处理模式有如下弊端。
订阅者依赖于主体,这样会造成模块之间的强耦合,而解耦是优秀设计一直追求的目标。
订阅者必须要得到主体的引用,才能订阅主体事件。在某些情况下这个要求很难达到,有时为了达到目的,引用会在几个对象之间不停传递。
为了克服这些弊端,我们来试试事件总线——EventAggregator。
参考设计模式中中介者模式的设计思想,我们引入一个事件总线充当中间人,无论订阅者也好,主体也好,都只和这个事件总线打交道。这个总线再以广播的形式把事件给广播出去——这也是通讯基本靠吼这个调侃的由来——同时,它带来的好处显而易见,再也不需要仅仅是为了订阅事件而辛苦的维持主体引用了。
这样的好处在于,无论有多少订阅者和主体,订阅关系的处理全权委托给了事件总线。同时双方只依赖于事件总线,不再相互依赖。而事件总线在工程里面一般位于Infrastructure这种基础公共类库里面,处于上层模块的主体和订阅者依赖于Infrastructure并无不妥。以这种依赖为代价换取之前的主体模块和订阅者模块之间的依赖,对于程序结构也是一大进步。
俗话说,光说不练假把式。让我们看一个例子,试着更深入的了解EventAggregator的好处。
设想一个游戏编辑器,有主界面,拥有地图选择器可以选择不同的世界,也可以切换不同的操作界面风格,而具体的地图编辑器,单元格编辑器则需要根据所选世界的不同而动态装载它们所呈现的内容。当然,编辑器们也需要对操作界面风格的改变做出响应,最后,所有这些改变都需要通知日志记录器。
可以想象,这一切如果用传统的事件模型会多么复杂,地图编辑器,单元格编辑和日志记录器需要依赖地图选择器和操作界面风格选择器,而且如果之后这些子编辑器有任何新的扩展,这些新类都需要依赖于选择器。
我们试着用EventAggregator来处理。
使用EventAggregator来处理事件订阅非常简单,只需如下几步。
using Prism;
using Prism.Events;
public class World{public string WorldName { get; set; }}public enum StyleColor{red,pink}public class Style{public string StyleName { get; set; }public StyleColor Color { get; set; }}public class WorldChangedEvent : PubSubEvent<World> //PubSubEvent的泛型实现,定义了该事件发布的时候可以传递的参数{}public class StyleChangedEvent : PubSubEvent<Style>{}
public class EventBus{private static Lazy<EventAggregator> _eventAggregator = new Lazy<EventAggregator>();public static EventAggregator Instance{get{return _eventAggregator.Value;}}}
public class CellEditor : IDisposable{Action _disposeAction = null;public CellEditor(){var token = EventBus.Instance.GetEvent<StyleChangedEvent>().Subscribe(OnStyleChanged); //订阅_disposeAction = () => { EventBus.Instance.GetEvent<StyleChangedEvent>().Unsubscribe(token); };}public void Dispose() //实现IDispose的目的在于当类实例销毁的时候,记得取消订阅。{_disposeAction?.Invoke();}private void OnStyleChanged(Style changedStyle){}}
public class WorldSelector{private World _currentWorld;public void ChangeWorld(World newWorld){_currentWorld = newWorld;EventBus.Instance.GetEvent<WorldChangedEvent>().Publish(newWorld);}}public class StyleSelector{private Style _currentStyle;public void ChangeStyle(Style newStyle){_currentStyle = newStyle;EventBus.Instance.GetEvent<StyleChangedEvent>().Publish(newStyle);}}
就这样简单几步,我们实现了事件总线模式,达成了代码类之间相互解耦的目的,同时,如果有新的编辑器加入,它们只需选择感兴趣的事件进行订阅,而无需先苦苦寻找主体引用。怎么样,是不是很神奇呢。
不过,就像那句软件行业的名言一样,没有银弹,虽然EventAggregator可以提供一些好处,但是仍然不要滥用,如果在涉及到的场景、事件的订阅者和主体之间的关系不是特别复杂的情况下,还是直接用传统事件模式的好。总结一下,EventAggregator的优缺点如下:
以上就是关于EventAggregator的简单介绍,希望对大家能有一些帮助!
本文发布于:2024-02-01 06:56:47,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170674180734712.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |