DDD | 05-什么是倉儲層
四、什么是倉儲層?
在DDD中,倉儲(Repository)是一種設計模式,它充當了領域層與數據存儲層之間的橋梁。倉儲的主要職責是提供一種抽象機制,使得領域對象(尤其是聚合根)可以被透明地持久化和檢索,而無需暴露底層的數據訪問技術細節給領域層。這樣設計的目的是為了保持領域模型的純凈性,讓業務邏輯不受數據訪問技術的影響,同時也促進了代碼的可測試性和可維護性。
主要特點
接口定義在領域層
- 倉儲接口定義了諸如保存(save)、查找(find)、更新(update)和刪除(delete)領域對象的方法,這些接口屬于領域層從一部分,確保了領域邏輯的獨立性
實現位于基礎設施層
- 雖然倉儲接口屬于領域層,但它的具體實現通常位于基礎設施層(Infrastructure Layer)。實現細節回依賴于具體的持久化技術,如關系數據庫、NoSQL數據庫、內存數據庫等
隔離領域層和數據訪問層
- 通過倉儲模式,領域層的對象可以不知道也不關心數據是如何存儲和檢索的。這有助于降低各層之間的耦合度,使得領域邏輯更加集中和純粹
提供一致的領域對象視圖
- 倉儲還負責管理領域對象的生命期,確保從存儲中檢索出來的對象符合領域模型的規則,例如,確保聚合的一致性
支持領域驅動設計的原則
- 如
Ubiquitous Language(通用語言)、業務優先和關注點分離等原則,通過倉儲的抽象,可以更好地在代碼中體現業務領域的概念和規則
問題探討
倉儲層和聚合根的區別是什么?
淺顯解釋
聚合根
- 想象你有一個裝滿東西的盒子,這個盒子就是聚合根。盒子里的東西(比如小玩具、文具等)代表聚合內的其他實體和值對象。盒子外面有個標簽,寫著里面有什么,這就是聚合根的標識。當你相拿走或放回盒子里的東西是,必須通過盒子(聚合根)來做,不能直接對盒子里的物品動手腳。聚合根確保盒子里的東西按規則擺放,保持整齊(即業務規則的一致性)
倉儲層
- 想象有一個大倉庫,里面存放著很多這樣的盒子(聚合根)。倉庫管理員(倉儲層)知道怎么找到每一個盒子,并且能幫你把盒子放進倉庫貨從倉庫里拿出來。你告訴管理員需要哪個盒子,管理員就會處理好一切,你不需要知道倉庫是怎么排列這些盒子的,也不用管它是用叉車還是傳送帶搬運的(即數據訪問的具體實現)
因此,聚合根是關于管理業務對象內部的規則和結構,而倉儲層是關于如何保存和獲取這些業務對象到數據存儲中。聚合根關注"做什么",倉儲層關注"怎么存取"。
術語解釋
聚合根
- 概念:聚合根是聚合中的一個特殊實體,它作為聚合的入口點,負責維護聚合內部的一致性。聚合是一組相關對象的集合,這些對象一起被當作一個單元來對待,對外界隱藏起內部結構和復雜性
- 職責:聚合根確保所有的業務規則在聚合內部得到遵守,它控制著對聚合內其他實體和值對象的訪問。外部對象不能直接訪問聚合內的非根實體,只能通過聚合根進行操作
- 示例:在一個電子商務系統中,訂單
Order可能是一個聚合根,它管理者訂單項OrderItem、客戶信息Customer等內部實體,確保例如訂單總額的計算規則得到正確執行
倉儲層
- 概念:倉儲是一個設計模式,它提供了一種抽象機制,用于透明地持久化和檢索領域對象,尤其是聚合根。它就像是一個集合或數據庫的模擬,允許領域層以面向對象的方式操作數據,而無需關心數據存儲的具體細節
- 職責:倉儲的主要職責包括保存
Save、查詢Find、更新Update和刪除Delete聚合根。它隔離了領域層和數據訪問層,使得領域邏輯可以獨立于具體的數據庫技術 - 示例:在一個電子商務系統中,
OrderRepository可能提供方法來查找特定ID的訂單、保存新訂單到數據庫、更新訂單狀態等,而不需要訂單類知道這些操作是如何與數據庫交互的
區別總結
- 目的不同:聚合根關注于業務邏輯的封裝和領域內的不變性維護,而倉儲關注于領域對象的持久化和檢索機制
- 層次位置:聚合根是領域層的一部分,直接參與業務邏輯的實現;倉儲雖然定義在領域層,但起具體實現通常位于基礎設施層,作為領域層與數據存儲之間的適配層
- 交互方式:外部組件通過倉儲來操作聚合根,而不會直接操作聚合內部的其他實體。聚合根則負責維護其內部狀態和業務規則的一致性
簡而言之,聚合根是領域模型中的核心構造,負責業務邏輯的實現和一致性保護;而倉儲是領域層與數據存儲之間的中介,確保領域對象能夠被持久化和檢索,同時保持領域模型的純粹性
代碼示例
寫一個訂單倉庫 (OrderRepository)
public interface OrderRepository {
/**
* 保存訂單聚合根。
* @param order 待保存的訂單聚合根對象,包含訂單的所有相關信息。
* @return 保存后的訂單聚合根對象。
*/
OrderAggregate save(OrderAggregate order);
/**
* 根據訂單ID查找訂單聚合根。
* @param orderId 待查找訂單的唯一標識。
* @return 如果找到,則返回包含訂單信息的Optional對象;否則返回空Optional。
*/
Optional<OrderAggregate> findById(UUID orderId);
/**
* 刪除訂單聚合根。
* @param order 待刪除的訂單聚合根對象。
*/
void delete(OrderAggregate order);
/**
* 更新訂單狀態。
* @param orderId 待更新訂單的狀態的唯一標識。
* @param newStatus 新的訂單狀態信息。
*/
void updateOrderStatus(UUID orderId, OrderStatusVO newStatus);
}
寫一個基于內存的訂單倉庫實現類OrderRepositoryImpl
public class OrderRepositoryImpl implements OrderRepository {
/**
* 使用HashMap存儲訂單聚合體,以訂單ID作為鍵,訂單聚合體作為值。
*/
private Map<UUID, OrderAggregate> orders = new HashMap<>();
/**
* 保存訂單聚合體。
*
* @param order 要保存的訂單聚合體。
* @return 返回保存的訂單聚合體。
*/
@Override
public OrderAggregate save(OrderAggregate order) {
orders.put(order.getOrderId(), order);
return order;
}
/**
* 根據訂單ID查找訂單聚合體。
*
* @param orderId 要查找的訂單ID。
* @return 返回找到的訂單聚合體的Optional,如果找不到則為empty。
*/
@Override
public Optional<OrderAggregate> findById(UUID orderId) {
return Optional.ofNullable(orders.get(orderId));
}
/**
* 刪除訂單聚合體。
*
* @param order 要刪除的訂單聚合體。
*/
@Override
public void delete(OrderAggregate order) {
orders.remove(order.getOrderId());
}
/**
* 更新訂單狀態。
*
* @param orderId 要更新狀態的訂單ID。
* @param newStatus 新的訂單狀態。
*/
@Override
public void updateOrderStatus(UUID orderId, OrderStatusVO newStatus) {
Optional<OrderAggregate> optionalOrder = findById(orderId);
optionalOrder.ifPresent(order -> {
order.changeStatus(newStatus);
});
}
}
OrderRepositoryImpl在DDD中所處位置?
屬于基礎設施層(Infrastructure Layer)的一部分?;A設施層提供技術性服務,如數據庫訪問、消息傳遞等,以支持領域層和應用層的功能。
具體分析,OrderRepository是一個接口,它定義了如何存取領域對象OrderAggregate到持久化存儲(如數據庫)中。這個接口屬于領域層或核心域(Core Domain),因為它表達了領域邏輯的一部分需求,即如何管理訂單聚合根的存儲和檢索。
而OrderRepositoryImpl作為接口OrderRepository的一個實現,通常駐留在基礎設施層。它實現了與具體數據存儲技術(如JDBC、Hibernate、Spring Data JPA等)交互的細節,確保領域層可以透過一個抽象的接口與這些底層技術解耦。這樣,領域層的代碼就不需要關心數據是如何被存儲或檢索的,從而提高了代碼的可維護性和靈活性。

浙公網安備 33010602011771號