文章目錄
- 引言:DDD戰術模式的重要性
- 一、DDD中的工廠模式
- 1.1 工廠模式的核心概念
- 1.2 工廠模式的三種實現方式
- 1.2.1 簡單工廠方法
- 1.2.2 工廠類
- 1.2.3 抽象工廠模式
- 1.3 工廠模式的適用場景
- 1.4 實際案例:電商訂單系統
- 二、表意接口模式
- 2.1 表意接口
- 2.2 表意接口的實現要點
- 2.2.1 命名規范
- 2.2.2 方法設計
- 2.3 表意接口的優勢
- 2.4 實際案例:庫存管理系統
- 三、工廠模式與表意接口的協同應用
- 3.1 結合使用的優勢
- 3.2 綜合案例:用戶注冊系統
- 3.3 反模式與常見錯誤
- 四、總結
引言:DDD戰術模式的重要性
- 在領域驅動設計(DDD)中,戰術模式是實現領域模型的關鍵工具。今天我們將深入探討兩個核心模式:工廠模式(Factory)和表意接口(Intention-Revealing Interfaces)模式。這些模式不僅能提升代碼質量,還能使領域邏輯更加清晰明確。
一、DDD中的工廠模式
1.1 工廠模式的核心概念
工廠模式在DDD中負責封裝復雜對象的創建邏輯,其主要目的是:
- 保持領域對象的完整性
- 隱藏復雜的構造邏輯
- 提供一致的創建接口
- 避免領域模型泄露構造細節
1.2 工廠模式的三種實現方式
1.2.1 簡單工廠方法
public class Order {public static Order createOrder(Customer customer, List<OrderItem> items) {Order order = new Order();order.setCustomer(customer);order.setItems(items);order.setStatus(OrderStatus.CREATED);order.setCreatedDate(LocalDateTime.now());return order;}
}
1.2.2 工廠類
public class PaymentFactory {public Payment createCreditCardPayment(BigDecimal amount, CreditCard card) {CreditCardPayment payment = new CreditCardPayment();payment.setAmount(amount);payment.setCard(card);payment.setPaymentDate(LocalDateTime.now());return payment;}public Payment createBankTransferPayment(BigDecimal amount, BankAccount account) {// 實現細節...}
}
1.2.3 抽象工廠模式
public interface ShippingProviderFactory {ShippingProvider createDomesticProvider();ShippingProvider createInternationalProvider();
}public class FedexShippingFactory implements ShippingProviderFactory {// 具體實現...
}
1.3 工廠模式的適用場景
- 復雜對象構造:當對象構造涉及多個步驟或復雜邏輯時
- 聚合根創建:確保聚合根及其內部實體的一致性
- 多態對象創建:需要根據條件創建不同類型的對象
- 重建持久化對象:從數據庫重建領域對象時
1.4 實際案例:電商訂單系統
public class OrderFactory {public Order createOrder(Customer customer, List<Product> products, Discount discount) {// 驗證業務規則if (customer.isBlocked()) {throw new CustomerBlockedException();}// 創建訂單聚合根Order order = new Order();order.setOrderNumber(generateOrderNumber());order.setCustomer(customer);order.setStatus(OrderStatus.PENDING);// 創建訂單項List<OrderItem> items = products.stream().map(p -> createOrderItem(p, discount)).collect(Collectors.toList());order.setItems(items);// 計算總價order.calculateTotal();return order;}private OrderItem createOrderItem(Product product, Discount discount) {// 實現細節...}
}
二、表意接口模式
2.1 表意接口
表意接口(Intention-Revealing Interfaces)是指通過接口名稱和方法簽名就能清晰表達其意圖和行為的接口設計方式。其核心原則是:
- 自描述性:無需查看實現就能理解其目的
- 領域一致性:使用領域專家熟悉的術語
- 行為明確:方法名準確反映其行為
2.2 表意接口的實現要點
2.2.1 命名規范
- 不良示例:
public interface OrderService {void process(Object data);
}
- 良好示例:
public interface OrderProcessing {OrderConfirmation placeOrder(ShoppingCart cart);void cancelOrder(OrderNumber orderNumber);OrderStatus checkOrderStatus(OrderNumber orderNumber);
}
2.2.2 方法設計
- 不良示例:
public class Account {public void update(BigDecimal amount) {// 實現細節...}
}
- 良好示例:
public class BankAccount {public void deposit(Money amount) {// 存款操作}public void withdraw(Money amount) throws InsufficientFundsException {// 取款操作}public void transfer(Money amount, BankAccount target) {// 轉賬操作}
}
2.3 表意接口的優勢
- 提高代碼可讀性:減少理解代碼所需的時間
- 降低認知負荷:開發者可以快速理解領域邏輯
- 減少文檔依賴:代碼自身就是最好的文檔
- 促進統一語言:強化團隊對領域術語的使用
2.4 實際案例:庫存管理系統
- 不良設計:
public class Inventory {public void adjust(int id, int qty) {// 實現細節...}
}
- 表意接口設計:
public class InventoryManagement {public StockLevel receiveStock(ProductId product, Quantity quantity) {// 入庫操作}public StockLevel reserveStock(ProductId product, Quantity quantity) throws OutOfStockException {// 預留庫存}public void fulfillReservation(ReservationId reservation) {// 完成預留}public StockReport generateStockReport(ProductCategory category) {// 生成庫存報告}
}
三、工廠模式與表意接口的協同應用
3.1 結合使用的優勢
- 當工廠模式與表意接口結合使用時,可以產生更強大的效果:
- 清晰的創建語義:工廠方法名明確表達創建意圖
- 一致的構造約束:通過工廠確保對象始終有效
- 簡化的客戶端代碼:調用方只需關注"做什么"而非"怎么做"
3.2 綜合案例:用戶注冊系統
public interface UserRegistration {User registerNewCustomer(CustomerRegistrationForm form);User registerAdminUser(AdminRegistrationRequest request);User inviteTeamMember(TeamMemberInvitation invitation);
}public class UserFactoryImpl implements UserRegistration {public User registerNewCustomer(CustomerRegistrationForm form) {// 驗證表單數據validateRegistrationForm(form);// 創建用戶聚合User user = new User();user.setUsername(form.getEmail());user.setPassword(encryptPassword(form.getPassword()));user.setRoles(Set.of(Role.CUSTOMER));user.setStatus(UserStatus.ACTIVE);// 創建客戶實體Customer customer = new Customer();customer.setUser(user);customer.setPersonalDetails(form.getPersonalDetails());user.setCustomerProfile(customer);return user;}// 其他方法實現...
}
3.3 反模式與常見錯誤
-
通用工廠:避免創建過于通用的工廠接口
// 不良設計 public interface GenericFactory {Object create(String type); }
-
模糊命名:工廠方法名應明確表達創建的對象的類型和意圖
// 不良設計 public class PaymentCreator {public Payment make(String type) {// 實現細節...} }// 良好設計 public class PaymentMethodFactory {public CreditCardPayment createCreditCardPayment(CardDetails card) {// 實現細節...} }
-
泄露實現細節:接口不應暴露內部實現機制
// 不良設計 public interface OrderService {void saveToDatabase(Order order); }// 良好設計 public interface OrderRepository {void save(Order order); }
四、總結
- 工廠模式和表意接口模式是DDD戰術設計中相輔相成的兩個重要模式。工廠模式通過封裝對象創建邏輯來保證領域對象的完整性和一致性,而表意接口模式則通過清晰的命名和設計使領域意圖更加明確。
在實際應用中,我們應該:
- 為復雜對象創建專門的工廠,特別是聚合根
- 使用領域術語命名工廠方法和接口
- 確保接口名稱準確反映其行為和意圖
- 通過工廠執行必要的業務規則驗證
- 保持接口的簡潔性和專注性