TypeScript如何實現DDD的值物件?
值物件是領域驅動設計的主要元件之一。這是TypeScript中的一個簡單的Value Object類。
在領域驅動設計中,值物件是幫助我們建立豐富且封裝的域模型的兩個原始概念之一。
實體和價值物件這兩個概念。
透過了解它與實體的不同之處,可以最好地理解值物件。它們的主要區別在於我們如何確定兩個值物件之間的身份標識以及我們如何確定兩個實體之間的身份標識。
實體身份標識
當我們關心模型的身份標識並能夠將該身份與模型的其他例項區分開來時,我們使用實體來建模域概念。
在我們確定身份的方式幫助我們確定它是否是一個實體或值物件。
一個常見的例子是為使用者建模。
在這個例子中,我們假設一個User是一個實體,因為我們確定兩個不同例項之間差異的方式是透過User的唯一識別符號辨別的。
我們在這裡使用的唯一識別符號是隨機生成的UUID或自動遞增的SQL ID,它們成為我們可以用來從某些永續性技術查詢的主鍵。
值物件
使用Value Objects,我們透過兩個例項的結構相等來建立身份標識。
意味著兩個物件具有相同的內容。這與引用相等/同一性不同,這意味著兩個物件是相同的。
為了識別彼此的兩個值物件,我們檢視物件的實際內容並基於此進行比較。
例如,實體User上可能存在屬性Name。我們如何判斷兩個Name是否相同?
這非常類似於比較兩個字串,對嗎?
"Nick Cave" === "Nick Cave" // true "Kim Gordon" === "Nick Cave" // false |
這很簡單。
我們User可能看起來像這樣:
interface IUser { readonly name: string } class User extends Entity<IUser> { public readonly name: string; constructor (props: IUser) { super(props); this.name = props.name; } } |
如果我們想限制使用者名稱的長度怎麼辦?假設它不能超過100個字元,並且必須至少為2個字元。
一種天真的方法是在建立此使用者的例項之前編寫一些驗證邏輯,可能在服務中:
class CreateUserService { public static createUser (name: string) : User{ if (name === undefined || name === null || name.length <= 2 || name.length > 100) { throw new Error('User must be greater than 2 chars and less than 100.') } else { return new User(name) } } } |
這不太理想。如果我們想要處理編輯使用者的名字怎麼辦?
class EditUserService { public static editUserName (user: User, name: string) : void { if (name === undefined || name === null || name.length <= 2 || name.length > 100) { throw new Error('User must be greater than 2 chars and less than 100.') } else { user.name = name; // save } } } |
- 這不是真正適合這樣做的地方。
- 我們剛剛重複了相同的驗證邏輯。
我們最終會將過多的域邏輯和驗證放入服務中,而模型本身並沒有準確地封裝域邏輯。
我們稱之為貧血領域模型。
我們引入了值物件類來封裝應該進行驗證的位置,並滿足模型的不變數(驗證和域規則)。
如果我們要為name屬性建立一個類,我們可以共同定位name該類本身的所有驗證邏輯。
我們還將使constuctor私有,並使用一個靜態工廠方法來執行必須滿足的前提條件,以便使用建立有效name的構造器。
interface IName { value: string } class Name extends ValueObject<IName> { private constuctor (props: IName) { super(props); } public static create (name: string) : Name { if (name === undefined || name === null || name.length <= 2 || name.length > 100) { throw new Error('User must be greater than 2 chars and less than 100.') } else { return new User(name) } } } |
值物件類
這是一個Value Object類的示例。
import { shallowEqual } from "shallow-equal-object";
interface ValueObjectProps {
[index: string]: any;
}
/**
* @desc ValueObjects are objects that we determine their
* equality through their structrual property.
*/
export abstract class ValueObject<T extends ValueObjectProps> {
public readonly props: T;
constructor (props: T) {
this.props = Object.freeze(props);
}
public equals (vo?: ValueObject<T>) : boolean {
if (vo === null || vo === undefined) {
return false;
}
if (vo.props === undefined) {
return false;
}
return shallowEqual(this.props, vo.props)
}
}
看看equals方法。請注意,我們使用shallowEquals它來確定相等性。這是一種完成結構相等的方法。
相關文章
- DDD實體值物件的equals和hashcode方法實現 - wimdeblauwe物件
- DDD的實體、值物件、聚合根的基類和介面:設計與實現物件
- DDD中實體與值物件是幹什麼的物件
- 從DDD中實體和值物件的逆向思考想到的物件
- 使用Typescript實現DDD領域建模 - Matthew de NobregaTypeScript
- DDD值物件:被遺忘的價值 – SoftwareMill Tech Blog物件REM
- 類似DDD的值物件的Java中新的值型別ValueType -jaxenter物件Java型別
- 向banq老師請教:ddd中的值物件物件
- __weak如何實現物件值自動設定為nil的物件
- cqrs模式下ddd中的domain service如何實現模式AI
- 如何實踐DDD?
- ThinkJS 3.0 如何實現對 TypeScript 的支援JSTypeScript
- 如何實現DDD事件建模的詳細步驟 - goeleven事件Go
- 如何實現物件的深度克隆物件
- 值物件如何共享物件
- 多型, DDD如何體現多型
- DDD | 03-什麼是實體物件物件
- 值物件,實體物件
- Java實現DDD中UnitOfWorkJava
- 使用Akka實現Reactive DDDReact
- TypeScript 類實現介面TypeScript
- DDD深思,物件裝備模型物件模型
- 實體和值物件物件
- 用Scala和Akka實現DDD
- 在spring和hibernate框架下如何實現DDD思想?Spring框架
- 實現TypeScript中的互斥型別TypeScript型別
- DDD專案現在實施的問題
- 「極速上手TypeScript」TypeScript進階“物件”TypeScript物件
- JS 物件如何實現深複製JS物件
- 如何在Typescript中定義Promise的返回值型別TypeScriptPromise型別
- ERP專案的價值如何實現(轉)
- 如何實現函式返回多個值函式
- DDD中實現業務規則的驗證 - Marcin
- 用例驅動實現DDD的方法 - codex
- DDD的函數語言程式設計實現函數程式設計
- TypeScript 數值型別TypeScript型別
- TypeScript與物件導向TypeScript物件
- 如何將物件拼接成get傳值的形式物件