再談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基於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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM