簡體   English   中英

如何使用 ddd 實現狀態模式

[英]how to implement state pattern using ddd

我有一個關於狀態模式以及如何使用 DDD 實現它的問題。 就我對狀態模式的理解而言,該模式用於處理不同狀態之間的轉換,因此每個狀態都有責任處理系統必須執行的操作才能轉換到新狀態。 為此,使用多態,每個狀態都可以是它自己的一個類,它擴展一個基類,實現從一個狀態到另一個狀態的轉換,遵循定義可能轉換的圖。

我一直在尋找有關如何使用 DDD 執行此操作的信息,並且在其他網站中,我發現了這個使用枚舉的網站。

http://nurkiewicz.blogspot.co.uk/2009/09/state-pattern-introducing-domain-driven.html

使用枚舉的原因是您可以將當前狀態(在這種情況下是枚舉的名稱)保存到存儲庫,以便稍后重新創建您的聚合。 因此,按照狀態模式定義,狀態可以接收不同的參數(例如,字段的新值),因此上下文(在這種情況下是聚合)可以轉換到新狀態並更新其字段,從而使狀態保持一致. 這意味着,狀態將負責更新聚合的值。

我的問題是,這是正確的做法嗎? 據我所知,在 DDD 中,聚合是知道其內部結構的聚合,每當必須更改聚合內的實體時,聚合必須公開一個方法,該方法稍后將調用該實體來更改其值。 通過這種方式,實體被封裝在聚合內部,並且不能從聚合外部直接訪問它們。

但是使用狀態模式的這種實現,改變聚合的是實體(或值對象,我不知道如何調用狀態)。 您甚至可以直接使用枚舉並在其中調用傳遞您的聚合的操作,並且聚合將被更改。

關於這個的另一個問題是; 當您必須為聚合提供某些取決於當前狀態的行為時,您在哪里進行實現? 在聚合內部,向狀態的基類添加更多操作以檢查狀態是一種還是另一種? 或者在狀態內部,因此狀態使用聚合來調用它公開的不同方法以提供該功能? 第一種方法意味着,根據您擁有的狀態數量,您將創建許多方法來檢查您是否處於適合您的目的的正確狀態。 另一個將暗示這再次是協調聚合必須調用其內部的方式的狀態。

對不起,如果這個問題以前被問過。 我已經找了幾天,但找不到與我在這里問的類似的東西。

提前致謝。

編輯:

抱歉回復晚了,我在假期。

在我的情況下,狀態相當簡單。 它們將反映比賽的不同狀態(NEW、OPEN_REGISTRATION、CLOSED_REGISTRATION、IN_PROGRESS、FINISHED、CANCELLED)。 我想做的是按照我提供的鏈接中的方法對概念進行探索。

我的問題是:當聚合(上下文)必須做一些取決於狀態的事情(比如注冊一個玩家)時,你會在哪里保持這種邏輯? 在上下文中,首先檢查狀態類是否屬於 OpenRegistrationState 類型? 或者在狀態類中,在 OpenRegistrationState 中提供一個實現,將玩家存儲到上下文中(該方法需要上下文和玩家作為參數)並從其他類中拋出和異常?

好像用了第二種方法,context里面的邏輯很簡單,只需要調用當前狀態就可以了。 問題是,當你有許多依賴狀態來操作的不同方法時,你的狀態類將有大量不同的方法,其中只有一兩個會實現,而其他方法會拋出異常。 在這種情況下,我不知道忘記狀態模式並僅使用枚舉並在某些邏輯取決於當前狀態時檢查值是否會更容易。

狀態模式的上下文表示一個對象的行為取決於它的狀態,它的方法包含 if/then(或 case)邏輯,反映基於狀態的條件。 該模式提供了這些 case 語句的替代方案。

解決方案是為每個狀態創建類,實現一個公共接口。 依賴狀態的操作從上下文對象委托給它的當前狀態對象。 上下文對象指向反映其當前狀態的狀態對象。

因此,如果我理解您的問題,那么域對象(à la DDD)是上下文對象,您希望避免其中的大小寫邏輯。 否則,您不需要狀態模式(如果您願意,您可以立即停止閱讀,因為其余部分不適用)。

Craig Larman 的Applying UML and Patterns 3rd Edition 書中有一章是關於使用模式設計持久性框架的,還有一節是關於事務狀態和狀態模式的 我相信他的方法與DDD兼容,因為它已在此處定義 實際上,它是Scott AmblerPersistentObject 思想的變體

應用於持久域對象的狀態模式

領域類有狀態。 在這個例子中,狀態是關於持久性的: NewOldCleanOldDirtyOldDeleteDeleted 有關詳細信息,請參閱 Larman 的書。

我無法在上面的 PlantUML 圖像上輕松注釋的一些細節:

  • PObjectState抽象類具有每個方法(轉換)的默認無操作主體
  • 實現,例如OldDirtyState.commit(...)處理基於狀態的行為的實現。 對於持久性,這是有道理的,因為它們通常是與域邏輯無關的行為。 持久化對象的回滾基本相同。

Larman 有一個腳注指出“每當域對象類擴展技術服務類時,它應該暫停進行反射,因為它混合了架構問題(持久性和應用程序邏輯)。”

您沒有使用具體示例來說明您想要建模的 State 究竟是什么,所以我不確定這個示例是否適用。

如果您的狀態是一些橫切關注點,在您的域對象中引入了不需要的耦合,那么您必須問自己一個更糟糕的問題:域對象中的案例邏輯,或不需要的耦合。 設計是權衡,你必須選擇你的戰斗。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM