第三步——定義Claptrap,管理商品庫存
通過本篇閱讀,您便可以開始嘗試使用 Claptrap 實現業務了。
该文档仅适用于 0.7 及以下版本,若想要查看最新版本内容,请点击右上角进行切换。 :::
#
開篇摘要本篇,我通過實現"管理庫存"的需求來瞭解一下如何在已有的項目樣例中定義一個 Claptrap。
結合前一篇的基本步驟,定義 Claptrap 只要而外增加一些步驟就可以了。完整的步驟如下所示,其中標記為「新內容」的部分屬於本篇的區別於前篇的新內容:
- 定義 ClaptrapTypeCode (新內容)
- 定義 State (新內容)
- 定義 Grain 介面 (新內容)
- 實現 Grain (新內容)
- 註冊 Grain (新內容)
- 定義 EventCode
- 定義 Event
- 實現 EventHandler
- 註冊 EventHandler
- 實作 IInitialStateDataFactory (新內容)
- 修改 Controller
這是一個從下向上的過程,實際的編碼過程中開發也可以有所調整。
本篇實現的業務用例:
- 實現表示庫存資料的 SKU(Stock keeping Unit) 物件。
- 能夠對 SKU 進行更新和讀取。
#
定義 ClaptrapTypeCodeClaptrapTypeCode 是一個 Claptrap 的唯一編碼。其在 State 的識別,序列化等方面起到了重要的作用。
打開HelloClaptrap.Models
專案中的ClaptrapCodes
類。
添加 SKU 的 ClaptrapTypeCode。
#
定義 StateState 在 Actor 模式中代表了 Actor 物件當前的數據表現。
由於 Claptrap 是基於事件溯源模式的 Actor。因此定義恰好的 State 非常重要。
在該示例當中,我們只需要記錄當前 SKU 的庫存即可,因此,State 的設計非常的簡單。
在 HelloClaptrap.Models 项目添加 Sku 文件夹,并在该文件夹下创建 SkuState 类。
添加如下代碼:
Inventory 表示當前 SKU 的庫存。
IStateData
介面是框架中表示 State 的空介面,用於在泛型推斷時使用。
#
定義 Grain 介面定義 Grain 介面的定義,才能夠提供外部與 Claptrap 的互通性。
在 HelloClaptrap.IActors 项目中添加 ISkuGrain 接口。
添加介面以及 Attribute。
其中增加了以下內容:
- 標記了
ClaptrapState
,使得 State 與 Grain 進行關聯。 - 介面繼承了
IClaptrapGrain
,這是框架定義的 Grain 介面,這是依託於 Orleans 運行必須繼承的介面。 - 增加了 GetInventoryAsync 方法,表示「獲取當前庫存」。
- 增加了 UpdateInventoryAsync 方法,表示"增量更新當前庫存"。
diff > 0
表示增加庫存,diff < 0
表示減少庫存。 - 需要注意的是 Grain 的方法定義有一定限制。詳細可以參見《Developing a Grain》。
#
實現 Grain定義好 ISkuGrain 之後,便可以添加代碼進行實現。
在 HelloClaptrap.Actors 项目新建 Sku 文件夹,并在该文件夹中添加 SkuGrain 类。
其中增加了以下內容:
- 繼承
ClaptrapBoxGrain<SkuState>
並實現ISkuGrain
,ClaptrapBoxGrain
是框架定義的 Grain 基類,其中的泛型參數表示對應的 State 類型。 - 實現 GetInventoryAsync 方法,從 StateData 中讀取當前的庫存。
- 實現 UpdateInventoryAsync 方法,添加業務判斷代碼,若不滿足業務操作的條件則拋出異常。
- UpdateInventoryAsync 的最後我們現在拋出 NotImplementedException ,因為當前事件還沒有定義,需要等待後續的代碼實現。
- BizException 是一個自定義異常,可以自行添加。實際開發中也可以不使用拋出異常的方式表示業務中斷,改用狀態碼或者其他返回值也是可以的。
#
註冊 GrainClaptrap 對應的 Grain 需要在應用程式啟動時進行註冊,這樣框架才能掃描發現。
由於示例代碼採用的是程式集範圍內掃描,因此實際上不需要進行修改。
這裡指出發生註冊的位置:
打開HelloClaptrap.BackendServer
專案的Program
類。
因為ISkuGrain和SkuGrain分別於ICartGrain和CartGrain屬於同一程式集,因而此處不需要修改。
#
定義 EventCode前面我們已經實現了 Claptrap 的主要部分,但唯獨沒有完成更新庫存的操作。這是因為更新庫存是需要對 State 進行更新的。而我們都知道 Claptrap 是基於事件溯源的 Actor 模式,對 State 的更新需要通過事件才能完成。故而由這裡開始,我們來通過事件更新庫存。
EventCode 是 Claptrap 系統每個事件的唯一編碼。其在事件的識別,序列化等方面起到了重要的作用。
打开 HelloClaptrap.Models 项目中的 ClaptrapCodes 类。
添加「更新庫存」的 EventCode。
#
定義 EventEvent 是事件溯源的關鍵。用於改變 Claptrap 中的 State。並且 Event 會被持久化在持久層。
在 HelloClaptrap.Models 项目的 Sku/Events 文件夹下创建 InventoryUpdateEvent 类。
添加如下代碼:
- Diff 表示此次更新庫存的數額,
diff > 0
表示增加庫存,diff < 0
表示減少庫存。 - NewInventory 表示更新之後的庫存。此處,提前給出一個建議,但由於篇幅問題,不展開討論:建議在事件中包含 State 的更新後數據。
#
實現 EventHandlerEventHandler 用于将事件更新到 Claptrap 的 State 上。
在 HelloClaptrap.Actors 项目的 Sku/Events 文件夹下创建 InventoryUpdateEventHandler 类。
添加如下代碼:
- 因為事件中已經包含了更新后的庫存,故而直接對 StateData 進行賦值即可。
#
註冊 EventHandler實現並測試完 EventHandler 之後,便可以將 EventHandler 進行註冊,以便與 EventCode 以及 Claptrap 進行關聯。
打開HelloClaptrap.Actors
專案的SkuGrain
類。
使用 Attribute 進行標記,並修改 UpdateInventory Async 執行事件。
#
實現 IInitial StateDataFactory前面我們已經完成了庫存的查詢和更新。不過通常來說庫存有一個初始數額,我們本節在補充這部分邏輯。
在 HelloClaptrap.Actors 项目的 Sku 文件夹下创建 SkuStateInitHandler 类。
IInitialStateDataFactory
會在 Claptrap 初次啟動時被調用,用來創建 State 的初始值。- 注入
ISkuRepository
從資料庫中讀取 Sku 對應的庫存初始數額,具體的代碼此處不進行羅列,讀者可以查看樣例倉庫中的實現。
除了實現代碼之外,還需要進行註冊才會被調用。
打開HelloClaptrap.Actors
專案的SkuGrain
類。
#
修改 Controller前面的所有步驟完成之後,就已經完成了 Claptrap 的所有部分。但由於 Claptrap 無法直接提供與外部程式的互通性。因此,還需要在在 Controller 層增加一個 API 以便外部進行「讀取庫存」 的操作。
在 HelloClaptrap.Web 项目的 Controllers 文件夹下新建 SkuController 类。
- 新增 API 讀取特定 SkuId 的庫存。按照樣例代碼的實現,可以傳入
yueluo-123
得到庫存數額為 666。不存在的 SkuId 將會拋出異常。 - 此處沒有創建更新庫存的對外 API,因為本示例將在下篇進行下單購物時進行庫存操作,此處暫不需要 API。
#
小結至此,我們就完成了"管理商品庫存"這個簡單需求的所有內容。
你可以從以下位址來獲取本文章對應的原始程式碼: