用于领域驱动设计 (DDD) 的 TypeScript
领域驱动设计 (DDD) 是一种强大的方法,通过专注于核心业务领域及其相关逻辑来处理复杂的软件系统。TypeScript 具有强大的类型和现代功能,是有效实现 DDD 概念的绝佳工具。本文探讨了 TypeScript 和 DDD 之间的协同作用,提供了实用的见解、策略和示例,以弥合设计和代码之间的差距。
理解领域驱动设计
**核心概念**
**1. 无处不在的语言**
开发人员和领域专家使用共享语言进行协作,以减少沟通错误。
**2. 有界上下文**
明确分离领域的不同部分,确保特定环境中的自主性和清晰度。
**3. 实体和值对象**
**4. 聚合**
域对象集群被视为数据变更的单个单元。
**5. 存储库**
抽象持久性逻辑,提供对聚合的访问。
**6. 域事件**
当域内发生重大动作时发出的信号。
**7. 应用服务**
封装业务工作流和编排逻辑。
为什么 TypeScript 适合 DDD
**1. 静态类型**:强类型检查有助于明确地建模域逻辑。
**2. 接口**:强制执行组件之间的契约。
**3. 类:**自然地表示实体、值对象和聚合。
**4. 类型保护**:确保运行时的类型安全。
**5. 实用类型**:为动态域启用强大的类型转换。
实际实施
**1. 建模实体**
实体具有唯一的身份并封装行为。
class Product { constructor( private readonly id: string, private name: string, private price: number ) {} changePrice(newPrice: number): void { if (newPrice <= 0) { throw new Error("Price must be greater than zero."); } this.price = newPrice; } getDetails() { return { id: this.id, name: this.name, price: this.price }; } }
**2. 创建值对象**
值对象是不可变的,并且通过值进行比较。
class Money { constructor(private readonly amount: number, private readonly currency: string) { if (amount < 0) { throw new Error("Amount cannot be negative."); } } add(other: Money): Money { if (this.currency !== other.currency) { throw new Error("Currency mismatch."); } return new Money(this.amount + other.amount, this.currency); } }
**3. 定义聚合**
聚合确保边界内的数据一致性。
class Order { private items: OrderItem[] = []; constructor(private readonly id: string) {} addItem(product: Product, quantity: number): void { const orderItem = new OrderItem(product, quantity); this.items.push(orderItem); } calculateTotal(): number { return this.items.reduce((total, item) => total + item.getTotalPrice(), 0); } } class OrderItem { constructor(private product: Product, private quantity: number) {} getTotalPrice(): number { return this.product.getDetails().price * this.quantity; } }
**4. 实现存储库**
存储库抽象数据访问。
interface ProductRepository { findById(id: string): Product | null; save(product: Product): void; } class InMemoryProductRepository implements ProductRepository { private products: Map= new Map(); findById(id: string): Product | null { return this.products.get(id) || null; } save(product: Product): void { this.products.set(product.getDetails().id, product); } }
**5. 使用领域事件**
领域事件通知系统状态变化。
class DomainEvent { constructor(public readonly name: string, public readonly occurredOn: Date) {} } class OrderPlaced extends DomainEvent { constructor(public readonly orderId: string) { super("OrderPlaced", new Date()); } } // Event Handler Example function onOrderPlaced(event: OrderPlaced): void { console.log(`Order with ID ${event.orderId} was placed.`); }
**6. 应用服务**
应用服务协调工作流程并执行用例。
class OrderService { constructor(private orderRepo: OrderRepository) {} placeOrder(order: Order): void { this.orderRepo.save(order); const event = new OrderPlaced(order.id); publishEvent(event); // Simulated event publishing } }
7. 使用有界上下文
利用 TypeScript 的模块化功能来隔离有界上下文。
**示例结构:**
/src /sales - Product.ts - Order.ts - ProductRepository.ts /inventory - Stock.ts - StockService.ts /shared - DomainEvent.ts
高级功能
**灵活建模的条件类型**
type Response= T extends "success" ? { data: any } : { error: string };
**用于验证的模板文字类型**
type Currency = `${"USD" | "EUR" | "GBP"}`;