專案目錄結構
原文地址
什麼是DDD?
DDD 是 Domain-Driven Design 的縮寫。 其主要的思想是,我們在設計軟體時,先從業務出發,理解真實的業務含義,將業務中的一些概念吸收到軟體建模中來,避免造出“大而無用”軟體。也避免軟體設計沒有內在聯絡,否則一團散沙,無法繼續演進。
為什麼要使用DDD?
過去,最常用的架構是三層架構,最典型的是MVC。三層架構的問題就是控制層依賴業務層,業務層又依賴資料層。特別是在資料層為貧血模型下,會讓業務層的程式碼高速膨脹。在維護過程中,改了一點需求就會引發意想不到的bug,修復bug又會引起其他的bug。
貧血模型和充血模型
貧血模型
所謂貧血模型,是指Model 中,僅包含狀態(屬性),不包含行為(方法),採用這種設計時,需要分離出DB層,專門用於資料庫操作。
充血模型
Model 中既包括狀態,又包括行為,是最符合面向物件的設計方式。
業務層設計
我們在寫業務程式碼的時候,最終要的往往在業務層,控制層就是最一些引數校驗處理,資料層就是持久化資料。業務邏輯集中在業務層,在三層就夠中業務層往往依賴資料層,吧orm的model物件拿到業務層使用,這是出bug概率最大的問題。那我們能不能做出設計,在業務層,既不依賴控制層也不依賴資料層呢?
我們使用反向依賴的方式,讓資料層依賴業務層。
比如我們要查詢一些使用者的訂單資訊
type User struct { Id int Name string Password string Age uint8 } type Order struct { Id int Good string PayTime time.Time } type UserRepo interface { GetUsers(ctx context.Context,name string) ([]*User,error) } type OrderRepo interface { GetOrders(ctx context.Context,userId int) ([]*Order,error) } type UserUseCase struct { ur UserRepo or OrderRepo } func NewUserUseCase(ur UserRepo,or OrderRepo) *UserUseCase { return &UserUseCase{ ur:ur, or:or, } } func (uuc *UserUseCase) GetOrders(ctx context.Context,name string) ([]*Order,error) { users,err := uuc.ur.GetUsers(ctx,name) if err != nil || len(users) == 0 { return fmt.Errorf("xxx%w",err) } userId := users[0].Id return uuc.or.GetOrders(ctx,userId) }
在上面的例子中,在GetOrders
方法中呼叫介面Repos中的方法,把業務程式碼寫完之後,進行單元測試我們只要mock實現各個repo的介面就好。然後再持久層(資料層)實現這些repo方法,在方法中把PO轉成DO。在控制層使用NewUserUseCase建立UseCase。進行呼叫吧DO轉化成DTO返回。
當然在業務複雜時,usecase的方法要簡單,吧邏輯都封裝到domain service中。
DTO DO和PO
DTO: Data Transfer Object的縮寫。用於表示一個數據傳輸物件。DTO 通常用於不同服務或服務不同分層之間的資料傳輸。
BO: Business Object 的縮寫,用於表示一個業務物件。
PO: Persistant Object縮寫。用於資料庫中一條記錄對映成struct。