好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

再谈Prism中的EventAggregatorDDD

再谈Prism中的EventAggregatorDDD

再谈Prism中的EventAggregator--DDD

接 [从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,是技术选型和技术架构问题,不是DDD设计的概念。

 

 

分类:  .Net

标签:  C# ,  WPF ,  Prism

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于再谈Prism中的EventAggregatorDDD的详细内容...

  阅读:44次