領域設計 Entity與VO

2022-02-21 02:58:25 字數 2922 閱讀 8134

要理解entity和vo,需要先理解兩個概念:「狀態」和「標識」!我們先來聊聊「狀態」!

大家肯定都在**買過東西吧!在**購買商品後,會有乙個訂單,記錄了你購買的商品資訊、**、店鋪資訊、還有乙個特別重要的資訊,就是訂單狀態。通過這個訂單狀態,我們可以知道我們的購物流程現在進行到哪一步了。如果你猶豫了很久才下定決心購買了一件心儀已久的商品,你是不是很在意訂單狀態?時不時要重新整理一下頁面,看看訂單狀態是否顯示已送達了?

開發過系統的都知道,一般訂單狀態都是使用乙個欄位來表示的,比如status,不同的狀態就是給status賦不同的值。但是這個status就是「訂單狀態」嗎?難道狀態就是乙個字段?!

order
你有沒有想過,當我們說「狀態」的時候,我們實際上指的是什麼?

我們在很多場景下會用到「狀態」這個詞,比如:

以「你今天狀態不錯」這句為例,如果狀態就是乙個字段!那麼,「你今天狀態不錯」就是status=1?!「你今天狀態不行」就是status=0?!很明顯,這不合理!

如果「狀態」不是簡單的乙個字段的話,那麼「狀態」到底是什麼呢?

其實在架構風格:你真的懂rest嗎?已經提過了!文中對rest的解釋,有這麼一句:乙個由網頁組成的網路(乙個虛擬狀態機),使用者通過選擇鏈結在應用中前進(狀態遷移),導致下乙個頁面(應用的下乙個狀態的表述)被轉移給使用者,並且呈現給他們,以便他們來使用。

結合上面的幾個場景,你有沒有發現,「狀態」實際上表示的是「目標物件在當前時刻所呈現出的內容」!在軟體系統中通過乙個欄位來表示狀態只是一種簡化手段!

如無特殊說明,下面所提到的「狀態」指的是「目標物件在當前時刻所呈現出的內容」,而不是指狀態字段

既然「狀態」表示的是「當前時刻所呈現出的內容」!那麼說明了「狀態」是個快照/瞬態!也就是說,「目標物件」有多個「狀態」,「當前狀態」只是「目標物件」眾多「狀態」中的乙個!

圖中的小冊子就是「目標物件」,冊子的每一頁就是「狀態」,當前展示出來的那一頁就是「當前狀態」!

在理解了什麼是「狀態」以後,我們就可以來初步區分entity和vo了:

現在,問題又來了,對於vo來說,因為「狀態」是不可變的,我們就可以用其「狀態」來表示vo!但是對於entity來說,因為有多個「狀態」,且「狀態」是可變的,那我們如何來表示呢?以上面的order為例,假設同乙個買家在同乙個賣家那裡買了兩個同樣的商品,那兩個訂單裡的資訊都是一樣的,但是它是兩個不同的訂單,我們如何區分這兩個訂單呢?

說到「標識」,我們最先想到的是程式語言中的「引用」或「指標」!比如下面的**:

order ordera = new order("producta",...);

order orderb = new order("producta",...);

ordera.productname = "productb";

這解決了「區分相同狀態的不同entity」的問題,但是沒有解決entity有多個狀態的問題。因為「標識」指向的是目標物件的當前狀態。而且,很多程式語言中有個很大的問題,就是不區分「標識」和「狀態」!什麼意思呢?

隨著時間的改變,我們能獲取到電影的不同狀態,每個狀態是相互獨立的。但是實際上我們的**邏輯像下面這樣:

var movie1 = new movie();

movie1.setcurrentframe("第三幀");

var currentmovie = movie1

movie1.setcurrentframe("第四幀");

currentmovie // 還是第三幀嗎?

語言中的這種「標識」(我稱為「隱式標識」)還有另外乙個問題,就是無法跨系統。比如,在分布式系統中,需要保證兩個系統中的物件是同乙個物件,這種「隱式標識」是做不到的。

所以「隱式標識」並不能滿足我們的需求。我們需要「顯示標識」,「顯示標識」在現實中很常見:

在上面購物的列子中,就相當於給order乙個唯一標識,比如乙個唯一的訂單號:

order
給定訂單號以後,無論訂單的狀態如何變化,只要訂單號不變,那麼它就是同乙個訂單。

所以,「標識」是另乙個區分entity和vo的關鍵點:

注意標識並不一定只是乙個字段,可能是多個欄位的組合,這需要根據不同的業務邏輯來確定。比如在乙個學校系統裡,可以通過學年+班級+學號來標識乙個學生。

理解了標識和狀態,我們就可以來定義entity和vo了:

現在我們知道了什麼是entity,什麼是vo,那麼我們如何在系統中識別哪些物件是entity,哪些物件又是vo呢?

乙個物件是表示成entity還是vo,取決於系統的關注點。

我們還以**購物為例,假設你在某家店鋪買了個商品,質量很好。過了一段時間後,你想再買乙個,但是你記不得是哪家店了,於是你從已完成的訂單列表中點選商品想進去再次購買。但是你點進去後發現,商品下架了。

這是因為「商品」在「訂單系統」中是個vo,而在「商品管理系統」中是entity!其實很好理解:

在「商品管理系統」中,商品可以這樣表示:

product
而在「訂單系統」中,訂單是個entity,商品是個vo,可以這麼表示:

order

product

注意這裡的id並不是標識,這裡的id實際上退化成了狀態的一部分,保留這個id是為了和「商品管理系統」進行互動,通過id從商品管理系統中查詢商品。當然還有其它方式,例如儲存「商品管理系統」中該商品的歷史url。

本文從對「狀態」和「標識」的理解開始,一步步來解釋什麼是entity和vo,以及如何在系統中識別entity和vo。後面將進一步討論entity與vo的關係,以及與其它元件的關係,例如dto,service,resporitory,dao等

Java po與vo的區別

vo,值物件 value object po,持久物件 persisent object 它們是由一組屬性和屬性的get和set方法組成。從結構上看,它們並沒有什麼不同的地方。但從其意義和本質上來看是完全不同的。vo是用new關鍵字建立,由gc 的。po則是向資料庫中新增新資料時建立,刪除資料庫中資...

反射與單級VO操作

class employee public void setname string name public string get public void set string public string tostring 如果我們把要傳的屬性設定成stringlei 型別一次傳進去就會方面很多。首先...

領域驅動設計之我見 領域業務

談到領域驅動設計 ddd 人們很容易想到如下這張圖,那麼是不是你的軟體做了如下的分層設計就是領域驅動設計的了?顯然不是,以下分層只能說明的軟體做了分層架構,領域驅動設計的核心在領域模型,領域模型的核心在業務知識。如果能夠採用物件導向思維將業務抽象為恰當的模型,不管用什麼架構都稱得上領域驅動設計。在大...