亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Golang 和 DDD 領域建模

Golang 和 DDD 領域建模

Go
largeQ 2023-06-12 14:21:08
我最近一直在研究領域驅動設計,必須說這種類型的架構設計觸發了我的一些東西。當我嘗試將它的概念應用到我的 Go 項目時,我遇到了一些障礙。以下是一些示例方法,但我不確定要使用哪種方法。項目結構摘錄:├── api/├── cmd/├── internal/|   ├── base/|   |   ├── eid.go|   |   ├── entity.go|   |   └── value_object.go|   ├── modules/|   |   ├── realm/|   |   |   ├── api/|   |   |   ├── domain/|   |   |   |   ├── realm/|   |   |   |   |   ├── service/|   |   |   |   |   ├── friendly_name.go|   |   |   |   |   ├── realm.go|   |   |   |   |   └── realm_test.go|   |   |   |   └── other_subdomain/|   |   |   └── repository/|   |   |       ├── inmem/|   |   |       └── postgres/所有方法通用:package realm // import "git.int.xxxx.no/go/xxxx/internal/modules/realm/domain/realm"// base contains common elements used by all modulesimport "git.int.xxxx.no/go/xxxx/internal/base"方法#1:type Realm struct {   base.Entity   FriendlyName FriendlyName}type CreateRealmParams struct {    FriendlyName string}func CreateRealm(id base.EID, params *CreateRealmParams) (*Realm, error) {   var err error   var r = new(Realm)   r.Entity = base.NewEntity(id)   r.FriendlyName, err = NewFriendlyName(params.FriendlyName)   return r, err}type FriendlyName struct {    value string}var ErrInvalidFriendlyName = errors.New("invalid friendly name")func (n FriendlyName) String() string { return n.value }func NewFriendlyName(input string) (FriendlyName, error) {    if input == "" {        return ErrInvalidFriendlyName    }    // perhaps some regexp rule here...    return FriendlyName{value: input}, nil}使用這種方法,我認為從長遠來看會有很多重復的代碼,但至少 FriendlyName 值對象根據 DDD 要求是不可變的,并且可以附加更多方法。這里的友好名稱類型只是一個字符串,但不可變。這個結構讓我想起了 Java 代碼……在查找領域時,存儲庫層是否應該使用域模型中的設置方法來構造領域聚合?我嘗試將 DTO 實現放置在同一個包 (dto_sql.go) 中,該包對領域聚合進行編碼/解碼,但是將這個問題放在域包中感覺有點不對勁。如果您面臨與我相同的問題,知道任何其他方法或有任何需要指出的,我將非常有興趣收到您的來信!
查看完整描述

1 回答

?
aluckdog

TA貢獻1847條經驗 獲得超7個贊

你的選項 #1 對我來說看起來最好,但有一些額外的觀察(注意:我會堅持你的命名,這會使其中一些看起來有點矯枉過正......再次重要的是想法。

  • 而不是Entity我會說Realm代表一個AggregateRoot.

  • 這可以是隱式的,也可以內聯一個base.AggregateRoot.

  • 聚合根是域的訪問點,并確保其狀態始終一致。

  • 因此內部狀態Realm應該是不可變的。狀態變化通過函數發生。

  • 除非真的微不足道并且不太可能改變,否則我會FriendlyName在單獨的文件中實現值對象。

  • 域的一部分也是 a ,RealmRepository但這僅提供一個接口。

現在我正在使用 CQRS,它是對您的代碼片段中顯示的內容的擴展。在這個:

  • ChangeFriendlyName應用層中可能有一個命令處理程序。

  • 處理程序可以訪問存儲庫實現,例如InMemRealmRepository。

  • 可能會將 a 傳遞CreateRealmParams給命令,然后命令進行驗證。

  • Realm處理程序邏輯可能從從數據庫中獲取聚合開始。

  • 然后構造一個新的FriendlyName(也可以封裝在一個Realm函數調用中)。

  • Realm更新狀態和排隊事件的函數調用FriendlyNameChanged。

  • 命令處理程序將更改保存到 InMemory 數據庫。

  • 只有在沒有錯誤的情況下,命令處理程序才會Commit()在聚合上調用。

  • 一個或多個排隊的事件現在發布,例如通過EventBus,在需要的地方處理。

至于選項 #1 的代碼有些變化(希望我做對了)..

realm.go - 聚合根

type Realm struct {

? ?base.AggregateRoot


? ?friendlyName FriendlyName

}


// Change state via function calls. Not shown: event impl, error handling.

// Even with CQRS having Events is entirely optional. You might implement

// it solely to e.g. maintain an audit log.

func (r *Realm) ChangeFriendlyName(name FriendlyName) {

? ?r.friendlyName = name

? ?

? ?var ev = NewFriendlyNameChanged(r.id, name)


? ?// Queue the event.

? ?r.Apply(ev)

}


// You might use Params types and encapsulate value object creation,

// but I'll pass value objects directly created in a command handler.

func CreateRealm(id base.AID, name FriendlyName) (*Realm, error) {

? ?ar := base.NewAggregateRoot(id)


? ?// Might do some param validation here.


? ?return &Realm{

? ? ? ?AggregateRoot: ar,

? ? ? ?friendlyName: name,

? ?}, nil

}

friendlyname.go - 值對象


type FriendlyName struct {

? ? value string

}


// Domain error. Part of ubiquitous language.

var FriendlyNameInvalid = errors.New("invalid friendly name")


func (n FriendlyName) String() string { return n.value }


func NewFriendlyName(input string) (FriendlyName, error) {

? ? if input == "" {

? ? ? ? return FriendlyNameInvalid

? ? }

? ? // perhaps some regexp rule here...


? ? return FriendlyName{value: input}, nil

}


查看完整回答
反對 回復 2023-06-12
  • 1 回答
  • 0 關注
  • 195 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號