從DTO到充血模型

2021-10-10 12:44:08 字數 1389 閱讀 6393

充血模型是marting fowler提出的概念,表示乙個包含領域知識(業務邏輯)的物件。與充血模型相對的是貧血模型。貧血模型是偽裝成領域模型的資料容器(data holder)。貧血模型只包含getter/setter,沒有任何領域知識。乙個和貧血模型非常相近的概念是dto。dto只有getter/setter,負責在不同模組或層次之間傳遞資料。dto有其存在的意義,但並非適用於任何場景。dto負責進行資料傳輸,但不了解任何領域知識,因此不應該出現在領域模型中。如果dto侵入領域模型,就變成了貧血模型。

貧血模型為什麼會出現呢?按照grasp的資訊專家模式,職責應當分配給擁有執行該職責所需資訊的物件。dto不就是這樣的物件嗎?這個觀點混淆了業務流程和業務流程執行例項。業務流程是對業務資料執行的一些列操作步驟,業務流程執行例項是對於某個特定的業務資料,業務流程執行的具體過程。二者的關係類似於程式和程序。執行乙個業務流程所需要的資訊,並非輸入業務流程的特定資料,而是在業務流程中處理資料的步驟。dto所包含的,只是業務流程的輸入資料。所以,充血模型是乙個函式?

result process(dto dto);
這要視情況而定。如果業務邏輯比較簡單,可以把業務邏輯做成靜態函式,以dto為輸入。這就是所謂的領域服務。但如果業務邏輯比較複雜,需要拆分成多個方法,而這些方法又共享一些資料,那麼就要封裝成充血(領域)模型。

理解了充血模型、貧血模型和dto這3個概念,就可以得到從dto建立充血模型的方法:封裝業務邏輯,剝離傳輸職責。持久化是將資料從易失性儲存傳輸到非易失性儲存的過程,因此充血模型也不應當承擔持久化的職責。持久化職責應當由repository承擔。

listing 1: 貧血模型

public string fromaccountid;

public string toaccountid;

public int money;

}public class transferreplydto

public class transferservice

if (from.balance < money)

from.expend(money);

to.receive(money);

reply.code = 0;

reply.message = "成功";

}}listing 2: 充血模型

public class transferservice 

}public class transfer

if (!from.checkbalance(money))

from.expend(money);

to.receive(money);

result.code = 0;

result.message = "成功";

return result;

}}

從貧血到充血Domain Model

關於domain model的討論已經非常多了,炒炒冷飯,這裡是自己的一些做法。以workitem 工作流裡的工作項 作為例子 最開始的做法 乙個實體類叫做workitem,指的是乙個工作項或者稱為任務項 乙個dao類叫做workitemdao 乙個業務邏輯類叫做workitemmanager 或者...

從貧血到充血Domain Model

關於domain model的討論已經非常多了,炒炒冷飯,這裡是自己的一些做法。以workitem 工作流裡的工作項 作為例子 最開始的做法 乙個實體類叫做workitem,指的是乙個工作項或者稱為任務項 乙個dao類叫做workitemdao 乙個業務邏輯類叫做workitemmanager 或者...

從貧血到充血Domain Model

關於domain model的討論已經非常多了,炒炒冷飯,這裡是自己的一些做法。以workitem 工作流裡的工作項 作為例子 最開始的做法 乙個實體類叫做workitem,指的是乙個工作項或者稱為任務項 乙個dao類叫做workitemdao 乙個業務邏輯類叫做workitemmanager 或者...