zoukankan      html  css  js  c++  java
  • 再谈Prism中的EventAggregatorDDD

    [从Prism中学习设计模式之Event Aggregator模式]一文,上文中从源码的角度分析了Prism中EventAggregator的实现。

    Lz想通过本文再深入谈下EventAggregator,将自己对Prism项目组的设计意图的理解做下记录,并希望和其他对Prism有兴趣的兄弟一起探讨。

    对于Prism的设计团队来说,设计EventAggregator肯定是经过一番详细考虑的,不会像我们平时在项目中图怎么简单怎么偷懒怎么来~[耻远了]。通过对Prism的源码进行阅读,给Lz一个很强的感觉就是Prism大量运用了设计模式和领域设计的理念,随着对源码理解的深入,这种感觉越来越强,每个设计都可以在软件工程设计理论中找到理论依据^-^。

    好了,开篇结束,下面进入正题,了解EventAggregator前,我先来认识一个名词Aggregator。

    Aggregator,中文含义:聚合。这是DDD设计中一个非常重要的概念。

    参考:Eric Evans-Domain-Driven Design 一书中的定义:

    聚合(Aggregator)是一组领域(Domain)对象,包括实体(Entity Object)和值对象(Value Object)。这组(Group)Domain Object的组合(Union)来描述一个Full Domain Model。

    在实际应用中,Domain模型中不是每个Entity Object都能描述一个完整的领域概念。举例就拿GBTouch项目中的会议与议程的关系来说,系统需要为每个会议维护多个议程,此时议程是一个Entity实体,而不是值对象。这样Domain模型就存在会议和议程两个实体对象,而事实,议程对象离开会议对象没有任何的实际意义,议程对象依附于会议对象,完整的表达了“会议可以有多个议程,并对这些议程进行维护”的思想,而会议即为议程的聚合根(Aggregator Root)。同理,会议与表决项的关系也是一样的概念。

    回归正题,每个聚合都有一个根实体即为聚合根,这个根实体所表述一个Domain概念的主题,外部对象需要访问聚合内实体时,只能通过该聚合根访问。聚合确定了实体生命周期的关注范围。

      --这里引出的Domain对象的生命周期问题不是本文的讨论范围,大家可以google相关内容。

    我们来看下Prism是不是实现了聚合的概念,果不其然,在命名空间Microsoft.Practices.Prism.Events

     Prism定义了IEventAggregator接口,接口中定义了GetEvent方法

       TEventType GetEvent<TEventType>() where TEventType : EventBase, new();

    IEventAggregator接口对基于EventAggregator的实现进行了约束。泛型TEventType继承一个抽象类EventBase,EventBase包含了基本事件的行为抽象。

    这样就完成了一个经典的DDD设计。

      我们看下Prism提供的Demo StrokeUI, MockEventAgrregator(实则为一个聚合根)通过实现IEventAggregator对其进行约束,MockPriceUpdatedEventAggregator定义了一个价格变更事件:

     1     class MockEventAggregator : IEventAggregator
     2     {
     3         Dictionary<Type, object> events = new Dictionary<Type, object>();
     4         public TEventType GetEvent<TEventType>() where TEventType : EventBase, new()
     5         {
     6             return (TEventType)events[typeof(TEventType)];
     7         }
     8 
     9         public void AddMapping<TEventType>(TEventType mockEvent)
    10         {
    11             events.Add(typeof(TEventType), mockEvent);
    12         }
    13     }
     1     class MockPriceUpdatedEventAggregator : MockEventAggregator
     2     {
     3         public MockMarketPricesUpdatedEvent MockMarketPriceUpdatedEvent = new MockMarketPricesUpdatedEvent();
     4         public MockPriceUpdatedEventAggregator()
     5         {
     6             AddMapping<MarketPricesUpdatedEvent>(MockMarketPriceUpdatedEvent);
     7         }
     8 
     9         public class MockMarketPricesUpdatedEvent : MarketPricesUpdatedEvent
    10         {
    11             public bool PublishCalled;
    12             public IDictionary<string, decimal> PublishArgumentPayload;
    13             public EventHandler PublishCalledEvent;
    14 
    15             private void OnPublishCalledEvent(object sender, EventArgs args)
    16             {
    17                 if (PublishCalledEvent != null)
    18                     PublishCalledEvent(sender, args);
    19             }
    20 
    21             public override void Publish(IDictionary<string, decimal> payload)
    22             {
    23                 PublishCalled = true;
    24                 PublishArgumentPayload = payload;
    25                 OnPublishCalledEvent(this, EventArgs.Empty);
    26             }
    27         }
    28     }


    单元测试实现:

     1  [TestMethod]
     2         public void PublishedEventContainsTheUpdatedPriceList()
     3         {
     4             var eventAgregator = new MockPriceUpdatedEventAggregator();
     5             var marketFeed = new TestableMarketFeedService(eventAgregator);
     6             Assert.IsTrue(marketFeed.SymbolExists("STOCK0"));
     7 
     8             marketFeed.InvokeUpdatePrices();
     9 
    10             Assert.IsTrue(eventAgregator.MockMarketPriceUpdatedEvent.PublishCalled);
    11             var payload = eventAgregator.MockMarketPriceUpdatedEvent.PublishArgumentPayload;
    12             Assert.IsNotNull(payload);
    13             Assert.IsTrue(payload.ContainsKey("STOCK0"));
    14             Assert.AreEqual(marketFeed.GetPrice("STOCK0"), payload["STOCK0"]);
    15         }


    好了,通过本文,大家应该对Prism中EventAggregator基于DDD的设计有所概念,其实关于EventAggregator还涉及了CQRS的设计概念,Lz将另外开篇讲述。

    在园子里和Google上看到很多朋友都把Prism的EventAggregator用于WPF的UI层面,我想通过本文阐述EventAggregator于WPF的前端UI交互没有任何关系。

    推荐的用法:

    1.WPF UIControl Event通过Event to Command

      Prism: use CommandBehaviorsBase 实现 event to command

      MVVMLight: use i:Interaction.Triggers 实现 event to command(framework 4.0以上引用System.Windows.Interactivity.dll)

    2.Command

      Prism: DelegateCommand

      MVVMLight:ReleyCommand

    3.Command trigger domain Layer

      domain Layer实现domain model的行为和状态。

    至于ORM,持久化,NoSQL,不是Prism考虑的问题,Prism已实现对外部组件的抽象。至于你用NHibernate,EF,MongoDB还是CouchDB基于Repository,是Infrastructure Layer考虑的问题,也是技术选型和技术架构问题,不是DDD设计的概念。

    DDD Sytem Architecture Layer:[自底向上]

    • Infrastructure
    • Domain
    • Apllication
    • Presentation

     后记:

      关于EventAggregator涉及的Event-Sourceing概念,现在有个很不错的框架可供参考。

      Open Source Web:http://geteventstore.com/

      Git Link:https://github.com/eventstore/eventstore/wiki

      Nuget: Event Stroe

  • 相关阅读:
    C++雾中风景1:友元类与面向对象
    NFS服务器的安装与配置
    未来工作相关
    python 函数
    pycharm、sublime个性化设置
    hadoop中HDFS的NameNode原理
    Cat搭建遇坑记
    美团点评CAT监控平台研究
    阿里sentinel源码研究深入
    阿里熔断限流Sentinel研究
  • 原文地址:https://www.cnblogs.com/tmywu/p/3095748.html
Copyright © 2011-2022 走看看