用 F#和EventStore實現DDD領域驅動設計
用 F#和EventStore實現領域驅動設計:Domain-Driven Design with F# and EventStore - Lev Gorodinski
廢話少說,直接上程式碼,其庫存品種領域模型程式碼InventoryItem如下,注意是F函式語言:
從上面程式碼看出,應該是Command啟用一個Event,Event改變狀態。因為使用了函式語言特點,將Command Event和State比C更好地封裝。
應該是將InventoryItem.Event進行儲存持久化,以便下次回放追溯,實現Event Sourcing。
整個專案原始碼下載
廢話少說,直接上程式碼,其庫存品種領域模型程式碼InventoryItem如下,注意是F函式語言:
/// An inventory item. <p class="indent">[<RequireQualifiedAccess>] module InventoryItem /// Represents the state of an inventory item. type State = { isActive : bool; } with static member Zero = { isActive = false } /// An inventory item command. type Command = | Create of System.Guid * string | Deactivate | Rename of string | CheckInItems of int | RemoveItems of int /// An inventory item event. type Event = | Created of string | Deactivated | Renamed of string | ItemsCheckedIn of int | ItemsRemoved of int /// Applies a inventory item event to a state. let apply item = function | Created _ -> { item with State.isActive = true; } | Deactivated _ -> { item with State.isActive = false; } | Renamed _ -> item | ItemsCheckedIn _ -> item | ItemsRemoved _ -> item /// Assertions used to maintain invariants upon command execution. module private Assert = let validName name = if System.String.IsNullOrEmpty(name) then invalidArg "name" "The name must not be null." let validCount count = if count <= 0 then invalidArg "count" "Inventory count must be positive." let inactive item = if item.isActive = true then failwith "The item is already deactivated." /// Executes an inventory item command. let exec item = let apply event = let newItem = apply item event event function | Create(id, name) -> Created(name) |> apply | Deactivate -> item |> Assert.inactive Deactivated |> apply | Rename(name) -> name |> Assert.validName Renamed(name) |> apply | CheckInItems(count) -> count |> Assert.validCount ItemsCheckedIn(count) |> apply | RemoveItems(count) -> count |> Assert.validCount ItemsRemoved(count) |> apply <p class="indent"> |
從上面程式碼看出,應該是Command啟用一個Event,Event改變狀態。因為使用了函式語言特點,將Command Event和State比C更好地封裝。
EventStore.fs程式碼如下:
/// Integration with EventStore. <p class="indent">[<RequireQualifiedAccess>] module EventStore open System open System.Net open EventStore.ClientAPI /// Creates and opens an EventStore connection. let conn () = let conn = EventStoreConnection.Create() conn.Connect(IPEndPoint(IPAddress.Parse("127.0.0.1"), 1113)) conn /// Creates an event store functions with an InventoryItem-specific serializer. let make (conn:EventStoreConnection) (serialize:InventoryItem.Event -> string * byte array, deserialize: string * byte array -> InventoryItem.Event) = let streamId id = "InventoryItem-" + id.ToString().ToLower() let load id = let streamId = streamId id let eventsSlice = conn.ReadStreamEventsForward(streamId, 1, Int32.MaxValue, false) eventsSlice.Events |> Seq.map (fun e -> deserialize(e.Event.EventType, e.Event.Data)) let commit (id,expectedVersion) (e:InventoryItem.Event) = let streamId = streamId id let eventType,data = serialize(e) let metaData = [||] : byte array let eventData = new EventData(Guid.NewGuid(), eventType, true, data, metaData) if expectedVersion = 0 then conn.CreateStream(streamId, Guid.NewGuid(), true, metaData) conn.AppendToStream(streamId, expectedVersion, eventData) load,commit <p class="indent"> |
應該是將InventoryItem.Event進行儲存持久化,以便下次回放追溯,實現Event Sourcing。
Aggregate.fs是實現聚合狀態的持久化統一介面。非常類似狀態模式,包括切換狀態。
/// Aggregate framework. <p class="indent">[<RequireQualifiedAccess>] module Aggregate /// Represents an aggregate. type Aggregate<'TState, 'TCommand, 'TEvent> = { /// An initial state value. zero : 'TState; /// Applies an event to a state returning a new state. apply : 'TState -> 'TEvent -> 'TState; /// Executes a command on a state yielding an event. exec : 'TState -> 'TCommand -> 'TEvent; } type Id = System.Guid /// Creates a persistent command handler for an aggregate. let makeHandler (aggregate:Aggregate<'TState, 'TCommand, 'TEvent>) (load:Id -> 'TEvent seq, commit:Id * int -> 'TEvent -> unit) = fun (id,version) command -> let state = load id |> Seq.fold aggregate.apply aggregate.zero let event = aggregate.exec state command event |> commit (id,version) <p class="indent"> |
整個專案原始碼下載
[該貼被banq於2013-02-19 18:32修改過]
相關文章
- DDD領域驅動設計:領域事件事件
- DDD領域驅動設計pdf
- 領域驅動設計(DDD)實踐之路(一)
- 領域驅動設計的DDD與ddd - nick
- DDD-領域驅動設計示例
- 淺談DDD(領域驅動設計)
- 淺談 DDD 領域驅動設計
- DDD領域驅動設計:倉儲
- 【DDD】《如何運用領域驅動設計》彙總
- 實現領域驅動設計
- 領域驅動設計DDD和CQRS架構模式落地實踐架構模式
- 領域驅動設計(DDD)入門&概要
- DDD-領域驅動設計簡談
- dayatang/dddlib:DDD領域驅動設計庫
- 領域驅動設計 (DDD) 簡介 - jannikwempe
- 領域驅動設計(DDD)實踐之路(二):事件驅動與CQRS事件
- 聊一聊中臺和DDD(領域驅動設計)
- 領域驅動設計(DDD)高手養成記
- 什麼是領域驅動設計(DDD)?- mathias
- 去哪兒網領域驅動設計(DDD)實踐之路
- DDD領域驅動設計總結和C#程式碼示例C#
- 《實現領域驅動設計》筆記——領域、子域和限界上下文筆記
- 結合領域事件和微服務的實現領域驅動設計 - Alagarsamy事件微服務
- 什麼是DDD領域驅動設計的戰略設計?
- 什麼是DDD領域驅動設計的戰術設計?
- 使用領域驅動設計DDD和CQRS實現身份驗證的微服務原始碼專案微服務原始碼
- SoftwareMill實現領域驅動設計的經驗REM
- 《實現領域驅動設計》筆記——架構筆記架構
- 領域驅動設計(DDD)中模型的重要性 - Jeronimo模型
- 實現領域驅動設計 - 使用ABP框架 - 建立實體框架
- 什麼是DDD領域驅動設計的統一語言?
- 領域驅動設計示例
- MasaFramework -- 領域驅動設計Framework
- 理解領域驅動設計
- ABP與DDD領域驅動關係
- .NET領域驅動設計—看DDD是如何運用設計模式顛覆傳統架構設計模式架構
- 領域驅動模型DDD(二)——領域事件的訂閱/釋出實踐模型事件
- 實現領域驅動設計 - 使用ABP框架 - 儲存庫框架
- 領域驅動設計DDD不具備大規模落地的條件!