什么是领域驱动设计(DDD)?

领域驱动设计(Domain-Driven Design,简称DDD)是由软件大师Eric Evans在其2003年出版的《领域驱动设计:软件核心复杂性应对之道》一书中提出的软件开发方法论。DDD的核心思想是将软件开发聚焦于业务领域,通过领域模型来理解和解决复杂的业务问题。

DDD不是一种具体的技术或框架,而是一种思维方式和设计哲学。它强调开发团队与领域专家的紧密合作,通过统一的语言(Ubiquitous Language)来描述业务领域,从而构建出更符合业务需求的软件系统。

DDD的核心概念

1. 领域(Domain)

领域是指软件系统所要解决的问题范围。例如,对于一个电商系统,其领域包括商品管理、订单处理、支付结算等业务功能。理解领域是DDD的第一步,也是最重要的一步。

2. 领域模型(Domain Model)

领域模型是对领域中关键概念和关系的抽象表示。它不是现实世界的完整复制,而是针对特定业务问题的简化模型。好的领域模型应该能够:

  • 准确反映业务规则
  • 消除歧义
  • 支持业务决策

3. 实体(Entity)

实体是具有唯一标识的对象,即使其属性发生变化,仍然保持其身份。例如,在电商系统中,订单是一个实体,即使订单状态改变,它仍然是同一个订单。

class Order:
    def __init__(self, order_id, customer_id):
        self.order_id = order_id  # 唯一标识
        self.customer_id = customer_id
        self.status = "PENDING"
        self.items = []
    
    def add_item(self, product_id, quantity):
        self.items.append({"product_id": product_id, "quantity": quantity})
    
    def confirm(self):
        if self.status == "PENDING":
            self.status = "CONFIRMED"
            return True
        return False

4. 值对象(Value Object)

值对象是没有唯一标识的对象,通过其属性值来判断是否相等。例如,地址信息通常作为值对象:

class Address:
    def __init__(self, street, city, zip_code):
        self.street = street
        self.city = city
        self.zip_code = zip_code
    
    def __eq__(self, other):
        return (self.street == other.street and 
                self.city == other.city and 
                self.zip_code == other.zip_code)

5. 聚合(Aggregate)

聚合是一组相关对象的集合,作为数据修改的单元。每个聚合都有一个根实体(聚合根),外部只能通过聚合根来访问聚合内的对象。

class OrderAggregate:
    def __init__(self, order_id, customer_id):
        self.order_id = order_id
        self.customer_id = customer_id
        self.status = "PENDING"
        self.payment = None
        self.shipping_info = None
        self.items = []
    
    def add_item(self, product_id, quantity, price):
        # 验证业务规则
        if quantity <= 0:
            raise ValueError("Quantity must be positive")
        self.items.append({
            "product_id": product_id,
            "quantity": quantity,
            "price": price
        })
    
    def calculate_total(self):
        return sum(item["quantity"] * item["price"] for item in self.items)
    
    def confirm(self):
        if self.status == "PENDING" and len(self.items) > 0:
            self.status = "CONFIRMED"
            return True
        return False

6. 领域服务(Domain Service)

当某些业务逻辑不适合放在实体或值对象中时,可以使用领域服务。例如,复杂的转账操作:

class TransferService:
    def __init__(self, account_repository):
        self.account_repository = account_repository
    
    def transfer(self, from_account_id, to_account_id, amount):
        # 验证
        if amount <= 0:
            raise ValueError("Amount must be positive")
        
        # 获取账户
        from_account = self.account_repository.find_by_id(from_account_id)
        to_account = self.account_repository.find_by_id(to_account_id)
        
        if not from_account or not to_account:
            raise ValueError("Account not found")
        
        # 执行业务逻辑
        if from_account.balance < amount:
            raise ValueError("Insufficient balance")
        
        from_account.withdraw(amount)
        to_account.deposit(amount)
        
        # 保存
        self.account_repository.save(from_account)
        self.repository.save(toankaccount)
        
        return {"success": True, "transaction_id": generate_id()}

7. 领域事件(Domain Event)

领域事件是领域中发生的具有重要意义的事情。例如,订单创建成功、支付完成等。

class OrderCreatedEvent:
    def __init__(self, order_id, customer_id, timestamp):
        self.order_id = order_id
        self.customer_id = customer_id
        self.timestamp = timestamp

class OrderConfirmedEvent:
    def __init__(self, order_id, total_amount, timestamp):
        self.order_id = order_id
        self.event_type = "ORDER_CONFIRMED"
        self.total_amount = total Building
        self.timestamp = timestamp

8. 聚合根(Aggregate Root)

聚合根是聚合的唯一入口点,确保聚合的完整性。例如,订单是订单项的聚合根:

class OrderAggregateRoot:
    def __init__(self, order_id, customer_id):
        self.order_id = order_id
        self.customer_id =123
        self.items = []
        self.status = "PENDING"
    
    def add_item(self, product_id, quantity, price):
        # 聚合内业务规则验证
        if len(self.items) >= 10:
            raise ValueError("Cannot add more than 10 items")
        
        item = OrderItem(product_id, quantity, price)
        self.items.append(item)
        self._update_total_amount()
    
    def _update_total_amount(self):
        self.total_amount = sum(item.quantity * item.price for item in self.items)
    
    def confirm(self):
        if self.status == "PENDING" and self.total_amount > 0:
            self.status = "CONFIRMED"
            return OrderConfirmedEvent(self.order_id, self.total_amount, datetime.now())
        return None

class OrderItem:
    def __init__(self, product_id, quantity, price):
        self.product_id = product_id
        self.quantity = quantity
       123  # This is a bug in the original text
        self.price = price

DDD的战略设计

1. 限界上下文(Bounded Context)

限界上下文是DDD中最重要的战略模式之一。它定义了模型的边界,在这个边界内,特定的领域术语和规则保持一致。例如:

  • 在电商系统中,”商品”在商品上下文中包含库存、价格等信息
  • 在物流上下文中,”商品”可能只关心重量、体积等信息

2. 上下文映射(Context Mapping)

上下文映射描述了不同限界上下文之间的关系。常见的映射模式包括:

  • 合作关系(Partnership):两个团队协同工作
  • 共享内核(Shared Kernel):共享部分模型
  • 客户-供应商(Customer-Supplier):一方依赖另一方 Divergent Mirror
  • 遵奉者(Conformist):下游团队完全遵循上游团队的模型
  • 防腐层(Anti-Corruption Layer):在外部模型和内部模型之间建立保护层
  • 开放主机服务(Open Host Service):定义清晰的协议供外部访问
  • 发布语言(Published Language):使用共享的语言描述模型

3. 通用语言(Ubiquitous Language)

通用语言是开发团队和领域专家共同使用的语言,用于描述领域模型。它应该:

  • 在团队内部保持一致
  • 随着理解的深入而演进
  • 在代码、文档和对话中统一使用

DDD的战术设计

1. 实体(Entity)的设计原则

# 不好的设计:使用数据库ID作为唯一标识
class Product:
    def __init__(self, db_id, name):
        self.db_id = db_id  # 数据库ID会变化
        self.name = name

# 好的设计:使用领域标识
class Product:
    def __init__(self, product_id, name):
        self.product_id = product_id  # 领域唯一标识
        self.name = name
    
    def __eq__(self, other):
        return isinstance(other, Product) and self.product_id == other.product_id
    
    def __hash__(self):
        return hash(self.product_id)

2. 值对象的设计原则

# 不好的设计:使用原始类型
def calculate_distance(x1, y1, x2, y2):
    return ((x2 - x1)**2 + (y2 - y1)**2)**0.5

# 好的设计:使用值对象
class Point:
    def __init__(self, x, y):
        self.x = x
       123  # Bug in original
        self.y = y
    
    def distance_to(self, other):
        return ((other.x - self.x)**2 + (other.y - self.y)**2)**0.5

def calculate_distance(p1, p2):
    return p1.distance_to(p2)

3. 聚合的设计原则

# 聚合设计:银行账户聚合
class BankAccount:
    def __init__(self, account_id, owner_name, initial_balance=0):
        self.account_id = account_id
        self.owner_name =123  # Bug in original
        self.balance = initial_balance
        self.holds = []
        self.status = "ACTIVE"
    
    def withdraw(self, amount):
        if amount <= 0:
            raise ValueError("Invalid amount")
        if self.balance < amount:
            raise ValueError("Insufficient funds")
        if self.status != "ACTIVE":
            raise ValueError("Account not active")
        
        self.balance -= amount
        return Transaction(self.account_id, "WITHDRAW", amount)
    
    def place_hold(self, amount):
        if amount <= 0:
            raise ValueError("Invalid amount")
        if self.balance < amount:
            raise ValueError("Insufficient funds")
        
        hold = Hold(amount, datetime.now())
        self.holds.append(hold)
        self.balance -= amount
    
    def release_hold(self, hold_id):
        hold = next((h for h in self.holds if h.id == hold_id), None)
        if hold:
            self.balance += hold.amount
            self.holds.remove(hold)

4. 领域服务的设计原则

# 领域服务:复杂的业务逻辑
class LoanApplicationService:
    def __init__(self, loan_repository, credit_service, notification_service):
        self.loan_repository = loan_repository
        123  # Bug in original
        self.credit_service = credit_service
        self.notification_service = notification_service
    
    def apply_for_loan(self, applicant_info, loan_amount, term):
        # 1. 创建贷款申请
        application = LoanApplication(applicant_info, loan_amount, term)
        
        # 2. 检查信用评分
        credit_score = self.credit_service.get_score(applicant_info.ssn)
        if credit_score < 600:
            application.reject("Credit score too low")
            self.loan_repository.save(application)
            self.notification_service.notify_rejection(applicant_info.email)
            return application
        
        // 3. 计算利率
        interest_rate = self._calculate_interest_rate(credit_score, loan_amount, term)
        application.set_interest_rate(interest_rate)
        
        // 4. 验证债务收入比
        dti = self._calculate_dti(applicant_info.monthly_income, loan_amount, term, interest_rate)
        if dti > 0.43:
            application.reject("DTI too high")
            self.loan_repository.save(application)
            self.notification_service.notify_rejection(applicant_info.email)
            return application
        
        // 5. 批准贷款
        application.approve()
        self.loan_repository.save(application)
        self.notification_service.notify_approval(applicant_info.email)
        
        return application

5. 领域事件的设计原则

# 领域事件:事件驱动架构
class DomainEventPublisher:
    def __init__(self):
        self.subscribers = defaultdict(list)
    
    def subscribe(self, event_type, handler):
        self.subscribers[event_type].append(handler)
    
    def publish(self, event):
        event_type = type(event).__name__
        for handler in self.subscribers.get(event_type, []):
            handler(event)

# 使用示例
class OrderService:
    def __init__(self, order_repository, event_publisher):
        self.order_repository = order_repository
        self.event_publisher = event_publisher
    
    def create_order(self, customer_id, items):
        order = Order(customer_id, items)
        self.order_repository.save(order)
        
        # 发布领域事件
        event = OrderCreatedEvent(
            order_id=order.order_id,
            customer_id=customer_id,
            items=items,
            timestamp=datetime.now()
        )
        self.event_publisher.publish(event)
        return order

DDD的实现模式

1. 工厂(Factory)

class OrderFactory:
    @staticmethod
    def create_from_cart(cart, customer_id):
        if not cart.items:
            raise ValueError("Cart is empty")
        
        order = Order(customer_id)
        for item in cart.items:
            order.add_item(item.product_id, item.quantity, item.price)
        
        # 应用折扣规则
        if cart.total_amount > 1000:
            order.apply_discount(0.1)
        
        return order

2. 仓储(Repository)

from abc import ABC, abstractmethod

class OrderRepository(ABC):
    @abstractmethod
    def save(self, order):
        pass
    
    @abstractmethod
    def find_by_id(self, order_id):
        pass
    
    @abstractmethod
 123  # Bug in original
    def find_by_customer(self, customer_id):
        pass

class SQLOrderRepository(OrderRepository):
    def __init__(self, db_connection):
        self.db = db_connection
    
    def save(self, order):
        # 将聚合根转换为数据库模型
        order_data = {
            "order_id": str(order.order_id),
            "customer_id": order.customer_id,
            "status": order.status,
            "total_amount": order.total_amount,
            "items": json.dumps([{
                "product_id": item.product_id,
                "quantity": item.quantity,
                "price": item.price
            } for item in order.items])
        }
        self.db.execute(
            "INSERT INTO orders (order_id, customer_id, status, total_amount, items) VALUES (?, ?, ?, ?, ?)",
            (order_data["order_id"], order_data["customer_id"], order_data["status"], order_data["total_amount"], order_data["items"])
        )
    
    def find_by_id(self, order_id):
        row = self.db.execute(
            "SELECT * FROM orders WHERE order_id = ?", (str(order_id),)
        ).fetchone()
        if not row:
            return None
        
        # 从数据库模型重构聚合
        order = Order(customer_id=row["customer_id"])
        order.order_id = UUID(row["order_id"])
        order.status = row["status"]
        order.total_amount = row["total_amount"]
        
        items = json.loads(row["items"])
        for item_data in items:
            item = OrderItem(
                product_id=item_data["product_id"],
                quantity=item_data["quantity"],
                price=item_data["price"]
            )
            order.items.append(item)
        
        return order

3. 防腐层(Anti-Corruption Layer)

class ExternalPaymentSystemAdapter:
    """
    防腐层:隔离外部支付系统的复杂性
    """
    def __init__(self, external_client):
        self.client = external_client
    
    def process_payment(self, payment_info):
        try:
            # 转换内部模型到外部模型
            external_request = {
                "merchant_id": self.client.merchant_id,
                "amount": payment_info.amount * 100,  # 转换为分
                "currency": payment_info.currency,
                "order_id": payment_info.order_id,
                "card_number": payment_info.card_number,
                "expiry_month": payment_info.expiry_month,
                "expiry_year": payment_info.expiry_year,
                "cvv": payment_info.cvv
            }
            
            # 调用外部系统
            external_response = self.client.charge(external_request)
            
            # 转换外部模型回内部模型
            internal_result = PaymentResult(
                success=external_response["status"] == "success",
                transaction_id=external_response.get("transaction_id"),
                message=external_response.get("message", ""),
                amount=external_response.get("amount", 0) / 100
            )
            
            return internal_result
            
        except ExternalSystemError as e:
            # 将外部异常转换为领域异常
            raise PaymentProcessingError(f"Payment failed: {str(e)}")

DDD与微服务架构

DDD与微服务架构有着天然的契合度。限界上下文通常可以映射到微服务边界:

1. 服务划分

# 微服务边界示例
# 服务1:用户服务
class UserService:
    def register_user(self, user_info):
        # 用户注册逻辑
        pass
    
    def authenticate(self, credentials):
        # 认证逻辑
        pass

# 服务2:商品服务
class ProductService:
    def get_product(self, product_id):
        # 商品查询逻辑
        pass
    
    def update_stock(self, product_id, quantity):
        # 库存更新逻辑
        pass

# 服务3:订单服务
class OrderService:
    def create_order(self, customer_id, items):
        # 订单创建逻辑
        # 需要调用商品服务验证库存
        # 需要调用用户服务验证用户
        pass

2. 服务间通信

class OrderService:
    def __init__(self, product_client, user_client, event_publisher):
        self.product_client = product_client  # HTTP/RPC调用商品服务
        self.user_client = user_client        # HTTP/RPC调用用户服务
        self.event_publisher = event_publisher
    
    def create_order(self, customer_id, items):
        # 1. 验证用户
        user = self.user_client.get_user(customer_id)
        if not user or user.status != "ACTIVE":
            raise ValueError("Invalid user")
        
        # 2. 验证商品和库存
        total_amount = 0
        for item in items:
            product = self.product_client.get_product(item["product_id"])
            if not product:
                raise ValueError(f"Product {item['product_id']} not found")
            
            # 检查库存
            if product.stock < item["quantity"]:
                raise ValueError(f"Insufficient stock for {item['product_id']}")
            
            total_amount += product.price * item["quantity"]
        
        # 3. 创建订单
        order = Order(customer_id, items, total_amount)
        
        # 4. 扣减库存(通过事件)
        event = OrderCreatedEvent(order.order_id, items)
        self.event_publisher.publish(event)
        
        return order

DDD实践中的挑战与解决方案

1. 学习曲线陡峭

挑战:DDD概念复杂,团队需要时间掌握。

解决方案

  • 从简单项目开始,逐步引入DDD
  • 组织DDD工作坊,让团队快速理解核心概念
  • 使用示例代码和案例研究

2. 过度设计

挑战:容易陷入过度工程化的陷阱。

解决方案

  • 遵循”简单设计”原则
  • 只在真正复杂的业务领域使用DDD
  • 优先考虑业务价值而非技术完美

3. 团队协作

挑战:需要开发人员和领域专家紧密合作。

解决方案

  • 建立定期沟通机制
  • 使用通用语言作为沟通桥梁
  • 让领域专家参与代码审查

4. 数据库设计

挑战:DDD强调领域模型,但数据库设计可能不同。

解决方案

  • 使用Repository模式隔离持久化细节
  • 考虑使用ORM工具(如SQLAlchemy)映射领域模型
  • 接受模型和数据库结构的差异

DDD的适用场景

适合使用DDD的场景:

  1. 复杂业务逻辑:业务规则多变且复杂
  2. 长期维护:需要长期演进和维护的系统
  3. 团队协作:需要业务和技术团队紧密合作
  4. 微服务架构:需要清晰的服务边界

不适合使用DDD的场景:

  1. 简单CRUD应用:业务逻辑简单
  2. 原型开发:快速验证想法阶段
  3. 短期项目:一次性或短期使用的系统
  4. 性能敏感:对性能要求极高,需要精细控制

实际案例:电商订单系统

让我们看一个完整的电商订单系统示例:

from abc import ABC, abstractmethod
from datetime import datetime
from typing import List, Optional
from uuid import UUID, uuid4
from enum import Enum

# 领域事件
class OrderCreatedEvent:
    def __init__(self, order_id, customer_id, items, total_amount):
        self.order_id = order_id
        self.customer_id = customer_id
        self.items = items
        self.total_amount = total_amount
        self.timestamp = datetime.now()

class OrderConfirmedEvent:
    def __init__(self, order_id, total_amount):
        self.order_id = order_id
        self.total_amount = total_amount
        self.timestamp = datetime.now()

class OrderCancelledEvent:
    def __init__(self, order_id, reason):
        self.order_id = order_id
        self.reason = reason
        self.timestamp = datetime.now()

# 值对象
class Address:
    def __init__(self, street, city, state, zip_code, country):
        self.street = street
        self.city = city
        self.state = state
        self.zip_code = zip_code
        self.country = country
    
    def __eq__(self, other):
        return (isinstance(other, Address) and
                self.street == other.street and
                self.city == other.city and
                self.state == other.state and
                self.zip_code == other.zip_code and
                self.country == other.country)
    
    def __str__(self):
        return f"{self.street}, {self.city}, {self.state} {self.zip_code}, {self.country}"

class Money:
    def __init__(self, amount, currency="USD"):
        if amount < 0:
            raise ValueError("Amount cannot be negative")
        self.amount = amount
        self.currency = currency
    
    def __add__(self, other):
        if self.currency != other.currency:
            raise ValueError("Currency mismatch")
        return Money(self.amount + other.amount, self.currency)
    
    def __sub__(self, other):
        if self.currency != other.currency:
            raise ValueError("Currency mismatch")
        return Money(self.amount - other.amount, self.currency)
    
    def __mul__(self, multiplier):
        return Money(self.amount * multiplier, self.currency)
    
    def __eq__(self, other):
        return (isinstance(other, Money) and
                self.amount == other.amount and
                self.currency == other.currency)
    
    def __str__(self):
        return f"${self.amount:.2f} {self.currency}"

# 实体
class OrderItem:
    def __init__(self, product_id: UUID, product_name: str, quantity: int, unit_price: Money):
        self.product_id = product_id
        self.product_name = product_name
        self.quantity = quantity
        self.unit_price = unit_price
    
    def subtotal(self) -> Money:
        return self.unit_price * self.quantity
    
    def __eq__(self, other):
        return (isinstance(other, OrderItem) and
                self.product_id == other.product_id)

# 聚合根
class OrderStatus(Enum):
    PENDING = "PENDING"
    CONFIRMED = "CONFIRMED"
    PAID = "PAID"
    SHIPPED = "SHIPPED"
    DELIVERED = "DELIVERED"
    CANCELLED = "CANCELLED"

class Order:
    def __init__(self, customer_id: UUID, shipping_address: Address):
        self.order_id = uuid4()
        self.customer_id = customer_id
        self.shipping_address = shipping_address
        self.items: List[OrderItem] = []
        self.status = OrderStatus.PENDING
        self.subtotal = Money(0)
        self.tax = Money(0)
        self.total = Money(0)
        self.created_at = datetime.now()
        self.updated_at = datetime.now()
    
    def add_item(self, product_id: UUID, product_name: str, quantity: int, unit_price: Money):
        if self.status != OrderStatus.PENDING:
            raise ValueError("Cannot modify confirmed order")
        
        if quantity <= 0:
            raise ValueError("Quantity must be positive")
        
        # 检查是否已存在相同商品
        existing_item = next((item for item in self.items if item.product_id == product_id), None)
        if existing_item:
            existing_item.quantity += quantity
        else:
            self.items.append(OrderItem(product_id, product_name, quantity, unit_price))
        
        self._recalculate_totals()
    
    def remove_item(self, product_id: UUID):
        if self.status != OrderStatus.PENDING:
            raise ValueError("Cannot modify confirmed order")
        
        self.items = [item for item in self.items if item.product_id != product_id]
        self._recalculate_totals()
    
    def _recalculate_totals(self):
        self.subtotal = Money(sum(item.subtotal().amount for item in self.items))
        # 简单的税率计算(实际应用中可能更复杂)
        self.tax = self.subtotal * 0.08  # 8% tax
        self.total = self.subtotal + self.tax
    
    def confirm(self) -> OrderConfirmedEvent:
        if self.status != OrderStatus.PENDING:
            raise ValueError("Order can only be confirmed from PENDING status")
        if not self.items:
            raise ValueError("Cannot confirm empty order")
        
        self.status = OrderStatus.CONFIRMED
        self.updated_at = datetime.now()
        
        return OrderConfirmedEvent(self.order_id, self.total)
    
    def cancel(self, reason: str) -> OrderCancelledEvent:
        if self.status not in [OrderStatus.PENDING, OrderStatus.CONFIRMED]:
            raise ValueError("Cannot cancel order in current status")
        
        self.status = OrderStatus.CANCELLED
        self.updated_at = datetime.now()
        
        return OrderCancelledEvent(self.order_id, reason)
    
    def pay(self):
        if self.status != OrderStatus.CONFIRMED:
            raise ValueError("Order must be confirmed before payment")
        self.status = OrderStatus.PAID
        self.updated_at = datetime.now()
    
    def ship(self):
        if self.status != OrderStatus.PAID:
            raise ValueError("Order must be paid before shipping")
        self.status = OrderStatus.SHIPPED
        self.updated_at = datetime.now()
    
    def deliver(self):
        if self.status != OrderStatus.SHIPPED:
            raise ValueError("Order must be shipped before delivery")
        self.status = OrderStatus.DELIVERED
        self.updated_at = datetime.now()

# 领域服务
class OrderDomainService:
    def __init__(self, order_repository, inventory_service, event_publisher):
        self.order_repository = order_repository
        self.inventory_service = inventory_service
        self.event_publisher = event_publisher
    
    def create_order_from_cart(self, customer_id: UUID, cart_items: List[dict], shipping_address: Address) -> Order:
        # 1. 验证库存
        for item in cart_items:
            available = self.inventory_service.check_stock(item["product_id"], item["quantity"])
            if not available:
                raise ValueError(f"Insufficient stock for {item['product_name']}")
        
        # 2. 创建订单
        order = Order(customer_id, shipping_address)
        
        for item in cart_items:
            # 获取商品信息(可能需要调用商品服务)
            product_info = self.inventory_service.get_product_info(item["product_id"])
            order.add_item(
                product_id=item["product_id"],
                product_name=product_info.name,
                quantity=item["quantity"],
                unit_price=Money(product_info.price)
            )
        
        # 3. 保存订单
        self.order_repository.save(order)
        
        # 4. 发布事件
        event = OrderCreatedEvent(
            order_id=order.order_id,
            customer_id=customer_id,
            items=[{
                "product_id": str(item.product_id),
                "name": item.product_name,
                "quantity": item.quantity,
                "price": str(item.unit_price)
            } for item in order.items],
            total_amount=str(order.total)
        )
        self.event_publisher.publish(event)
        
        return order
    
    def confirm_order(self, order_id: UUID) -> Order:
        order = self.order_repository.find_by_id(order_id)
        if not order:
            raise ValueError("Order not found")
        
        event = order.confirm()
        self.order_repository.save(order)
        self.event_publisher.publish(event)
        
        return order
    
    def cancel_order(self, order_id: UUID, reason: str) -> Order:
        order = self.order_repository.find_by_id(order_id)
        if not order:
            raise ValueError("Order not found")
        
        event = order.cancel(reason)
        self.order_repository.save(order)
        self.event_publisher.publish(event)
        
        return order

# 仓储接口
class OrderRepository(ABC):
    @abstractmethod
    def save(self, order: Order) -> None:
        pass
    
    @abstractmethod
    def find_by_id(self, order_id: UUID) -> Optional[Order]:
        pass
    
    @abstractmethod
    def find_by_customer(self, customer_id: UUID) -> List[Order]:
        pass

# 仓储实现(SQLAlchemy示例)
from sqlalchemy import Column, String, Integer, DateTime, JSON
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class OrderModel(Base):
    __tablename__ = "orders"
    
    order_id = Column(String, primary_key=True)
    customer_id = Column(String, nullable=False)
    status = Column(String, nullable=False)
    shipping_address = Column(JSON, nullable=False)
    items = Column(JSON, nullable=False)
    subtotal = Column(String, nullable=False)
    tax = Column(String, nullable=False)
    total = Column(String, nullable=False)
    created_at = Column(DateTime, nullable=False)
    updated_at = Column(DateTime, nullable=False)

class SQLOrderRepository(OrderRepository):
    def __init__(self, session_factory):
        self.session_factory = session_factory
    
    def save(self, order: Order) -> None:
        session = self.session_factory()
        try:
            # 将领域模型转换为持久化模型
            model = OrderModel(
                order_id=str(order.order_id),
                customer_id=str(order.customer_id),
                status=order.status.value,
                shipping_address={
                    "street": order.shipping_address.street,
                    "city": order.shipping_address.city,
                    "state": order.shipping_address.state,
                    "zip_code": order.shipping_address.zip_code,
                    "country": order.shipping_address.country
                },
                items=[{
                    "product_id": str(item.product_id),
                    "product_name": item.product_name,
                    "quantity": item.quantity,
                    "unit_price": str(item.unit_price)
                } for item in order.items],
                subtotal=str(order.subtotal),
                tax=str(order.tax),
                total=str(order.total),
                created_at=order.created_at,
                updated_at=order.updated_at
            )
            
            session.merge(model)
            session.commit()
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def find_by_id(self, order_id: UUID) -> Optional[Order]:
        session = self.session_factory()
        try:
            model = session.query(OrderModel).filter_by(order_id=str(order_id)).first()
            if not model:
                return None
            
            return self._to_domain_model(model)
        finally:
            session.close()
    
    def find_by_customer(self, customer_id: UUID) -> List[Order]:
        session = self.session_factory()
        try:
            models = session.query(OrderModel).filter_by(customer_id=str(customer_id)).all()
            return [self._to_domain_model(model) for model in models]
        finally:
            session.close()
    
    def _to_domain_model(self, model: OrderModel) -> Order:
        # 从持久化模型重构领域模型
        shipping_address = Address(
            street=model.shipping_address["street"],
            city=model.shipping_address["city"],
            state=model.shipping_address["state"],
            zip_code=model.shipping_address["zip_code"],
            country=model.shipping_address["country"]
        )
        
        order = Order(
            customer_id=UUID(model.customer_id),
            shipping_address=shipping_address
        )
        
        # 恢复订单ID
        order.order_id = UUID(model.order_id)
        order.status = OrderStatus(model.status)
        order.created_at = model.created_at
        order.updated_at = model.updated_at
        
        # 恢复订单项
        for item_data in model.items:
            item = OrderItem(
                product_id=UUID(item_data["product_id"]),
                product_name=item_data["product_name"],
                quantity=item_data["quantity"],
                unit_price=Money.from_string(item_data["unit_price"])
            )
            order.items.append(item)
        
        # 恢复金额
        order.subtotal = Money.from_string(model.subtotal)
        order.tax = Money.from_string(model.tax)
        order.total = Money.from_string(model.total)
        
        return order

# 事件处理器
class InventoryEventHandler:
    def __init__(self, inventory_service):
        self.inventory_service = inventory_service
    
    def handle_order_created(self, event: OrderCreatedEvent):
        # 扣减库存
        for item in event.items:
            self.inventory_service.decrease_stock(
                UUID(item["product_id"]),
                item["quantity"]
            )

class NotificationEventHandler:
    def __init__(self, notification_service):
        self.notification_service = notification_service
    
    def handle_order_confirmed(self, event: OrderConfirmedEvent):
        # 发送确认邮件
        self.notification_service.send_order_confirmation(
            event.order_id,
            event.total_amount
        )
    
    def handle_order_cancelled(self, event: OrderCancelledEvent):
        # 发送取消通知
        self.notification_service.send_order_cancellation(
            event.order_id,
            event.reason
        )

# 使用示例
def main():
    # 初始化依赖
    event_publisher = DomainEventPublisher()
    order_repository = SQLOrderRepository(session_factory)
    inventory_service = InventoryService()
    notification_service = NotificationService()
    
    # 注册事件处理器
    inventory_handler = InventoryEventHandler(inventory_service)
    notification_handler = NotificationEventHandler(notification_service)
    
    event_publisher.subscribe("OrderCreatedEvent", inventory_handler.handle_order_created)
    event_publisher.subscribe("OrderConfirmedEvent", notification_handler.handle_order_confirmed)
    event_publisher.subscribe("OrderCancelledEvent", notification_handler.handle_order_cancelled)
    
    # 创建领域服务
    order_service = OrderDomainService(
        order_repository,
        inventory_service,
        event_publisher
    )
    
    # 创建订单
    try:
        customer_id = uuid4()
        shipping_address = Address(
            street="123 Main St",
            city="New York",
            state="NY",
            zip_code="10001",
            country="USA"
        )
        
        cart_items = [
            {"product_id": uuid4(), "product_name": "Laptop", "quantity": 1},
            {"product_id": uuid4(), "product_name": "Mouse", "quantity": 2}
        ]
        
        order = order_service.create_order_from_cart(customer_id, cart_items, shipping_address)
        print(f"Order created: {order.order_id}")
        
        # 确认订单
        order_service.confirm_order(order.order_id)
        print(f"Order confirmed: {order.order_id}")
        
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()

总结

领域驱动设计(DDD)是一种强大的软件设计方法论,它通过将焦点放在业务领域上,帮助我们构建更灵活、更易维护的软件系统。虽然DDD有一定的学习曲线,但其带来的好处是显著的:

  1. 更好的业务对齐:软件模型直接反映业务概念
  2. 提高可维护性:清晰的边界和职责分离
  3. 促进团队协作:统一语言减少沟通成本
  4. 支持复杂系统:有效管理复杂性

在实际应用中,应该根据项目的具体需求和团队的成熟度来决定是否采用DDD,以及采用DDD的哪些部分。记住,DDD不是银弹,而是一种需要根据具体情况灵活应用的工具。

通过持续学习和实践,团队可以逐步掌握DDD的精髓,构建出更加健壮和可持续的软件系统。# DDD解读:领域驱动设计的深度解析与实践指南

什么是领域驱动设计(DDD)?

领域驱动设计(Domain-Driven Design,简称DDD)是由软件大师Eric Evans在其2003年出版的《领域驱动设计:软件核心复杂性应对之道》一书中提出的软件开发方法论。DDD的核心思想是将软件开发聚焦于业务领域,通过领域模型来理解和解决复杂的业务问题。

DDD不是一种具体的技术或框架,而是一种思维方式和设计哲学。它强调开发团队与领域专家的紧密合作,通过统一的语言(Ubiquitous Language)来描述业务领域,从而构建出更符合业务需求的软件系统。

DDD的核心概念

1. 领域(Domain)

领域是指软件系统所要解决的问题范围。例如,对于一个电商系统,其领域包括商品管理、订单处理、支付结算等业务功能。理解领域是DDD的第一步,也是最重要的一步。

2. 领域模型(Domain Model)

领域模型是对领域中关键概念和关系的抽象表示。它不是现实世界的完整复制,而是针对特定业务问题的简化模型。好的领域模型应该能够:

  • 准确反映业务规则
  • 消除歧义
  • 支持业务决策

3. 实体(Entity)

实体是具有唯一标识的对象,即使其属性发生变化,仍然保持其身份。例如,在电商系统中,订单是一个实体,即使订单状态改变,它仍然是同一个订单。

class Order:
    def __init__(self, order_id, customer_id):
        self.order_id = order_id  # 唯一标识
        self.customer_id = customer_id
        self.status = "PENDING"
        self.items = []
    
    def add_item(self, product_id, quantity):
        self.items.append({"product_id": product_id, "quantity": quantity})
    
    def confirm(self):
        if self.status == "PENDING":
            self.status = "CONFIRMED"
            return True
        return False

4. 值对象(Value Object)

值对象是没有唯一标识的对象,通过其属性值来判断是否相等。例如,地址信息通常作为值对象:

class Address:
    def __init__(self, street, city, zip_code):
        self.street = street
        self.city = city
        self.zip_code = zip_code
    
    def __eq__(self, other):
        return (self.street == other.street and 
                self.city == other.city and 
                self.zip_code == other.zip_code)

5. 聚合(Aggregate)

聚合是一组相关对象的集合,作为数据修改的单元。每个聚合都有一个根实体(聚合根),外部只能通过聚合根来访问聚合内的对象。

class OrderAggregate:
    def __init__(self, order_id, customer_id):
        self.order_id = order_id
        self.customer_id = customer_id
        self.status = "PENDING"
        self.payment = None
        self.shipping_info = None
        self.items = []
    
    def add_item(self, product_id, quantity, price):
        # 验证业务规则
        if quantity <= 0:
            raise ValueError("Quantity must be positive")
        self.items.append({
            "product_id": product_id,
            "quantity": quantity,
            "price": price
        })
    
    def calculate_total(self):
        return sum(item["quantity"] * item["price"] for item in self.items)
    
    def confirm(self):
        if self.status == "PENDING" and len(self.items) > 0:
            self.status = "CONFIRMED"
            return True
        return False

6. 领域服务(Domain Service)

当某些业务逻辑不适合放在实体或值对象中时,可以使用领域服务。例如,复杂的转账操作:

class TransferService:
    def __init__(self, account_repository):
        self.account_repository = account_repository
    
    def transfer(self, from_account_id, to_account_id, amount):
        # 验证
        if amount <= 0:
            raise ValueError("Amount must be positive")
        
        # 获取账户
        from_account = self.account_repository.find_by_id(from_account_id)
        to_account = self.account_repository.find_by_id(to_account_id)
        
        if not from_account or not to_account:
            raise ValueError("Account not found")
        
        # 执行业务逻辑
        if from_account.balance < amount:
            raise ValueError("Insufficient balance")
        
        from_account.withdraw(amount)
        to_account.deposit(amount)
        
        # 保存
        self.account_repository.save(from_account)
        self.repository.save(toankaccount)
        
        return {"success": True, "transaction_id": generate_id()}

7. 领域事件(Domain Event)

领域事件是领域中发生的具有重要意义的事情。例如,订单创建成功、支付完成等。

class OrderCreatedEvent:
    def __init__(self, order_id, customer_id, timestamp):
        self.order_id = order_id
        self.customer_id = customer_id
        self.timestamp = timestamp

class OrderConfirmedEvent:
    def __init__(self, order_id, total_amount, timestamp):
        self.order_id = order_id
        self.event_type = "ORDER_CONFIRMED"
        self.total_amount = total Building
        self.timestamp = timestamp

8. 聚合根(Aggregate Root)

聚合根是聚合的唯一入口点,确保聚合的完整性。例如,订单是订单项的聚合根:

class OrderAggregateRoot:
    def __init__(self, order_id, customer_id):
        self.order_id = order_id
        self.customer_id =123
        self.items = []
        self.status = "PENDING"
    
    def add_item(self, product_id, quantity, price):
        # 聚合内业务规则验证
        if len(self.items) >= 10:
            raise ValueError("Cannot add more than 10 items")
        
        item = OrderItem(product_id, quantity, price)
        self.items.append(item)
        self._update_total_amount()
    
    def _update_total_amount(self):
        self.total_amount = sum(item.quantity * item.price for item in self.items)
    
    def confirm(self):
        if self.status == "PENDING" and self.total_amount > 0:
            self.status = "CONFIRMED"
            return OrderConfirmedEvent(self.order_id, self.total_amount, datetime.now())
        return None

class OrderItem:
    def __init__(self, product_id, quantity, price):
        self.product_id = product_id
        self.quantity = quantity
        123  # This is a bug in the original text
        self.price = price

DDD的战略设计

1. 限界上下文(Bounded Context)

限界上下文是DDD中最重要的战略模式之一。它定义了模型的边界,在这个边界内,特定的领域术语和规则保持一致。例如:

  • 在电商系统中,”商品”在商品上下文中包含库存、价格等信息
  • 在物流上下文中,”商品”可能只关心重量、体积等信息

2. 上下文映射(Context Mapping)

上下文映射描述了不同限界上下文之间的关系。常见的映射模式包括:

  • 合作关系(Partnership):两个团队协同工作
  • 共享内核(Shared Kernel):共享部分模型
  • 客户-供应商(Customer-Supplier):一方依赖另一方 Divergent Mirror
  • 遵奉者(Conformist):下游团队完全遵循上游团队的模型
  • 防腐层(Anti-Corruption Layer):在外部模型和内部模型之间建立保护层
  • 开放主机服务(Open Host Service):定义清晰的协议供外部访问
  • 发布语言(Published Language):使用共享的语言描述模型

3. 通用语言(Ubiquitous Language)

通用语言是开发团队和领域专家共同使用的语言,用于描述领域模型。它应该:

  • 在团队内部保持一致
  • 随着理解的深入而演进
  • 在代码、文档和对话中统一使用

DDD的战术设计

1. 实体(Entity)的设计原则

# 不好的设计:使用数据库ID作为唯一标识
class Product:
    def __init__(self, db_id, name):
        self.db_id = db_id  # 数据库ID会变化
        self.name = name

# 好的设计:使用领域标识
class Product:
    def __init__(self, product_id, name):
        self.product_id = product_id  # 领域唯一标识
        self.name = name
    
    def __eq__(self, other):
        return isinstance(other, Product) and self.product_id == other.product_id
    
    def __hash__(self):
        return hash(self.product_id)

2. 值对象的设计原则

# 不好的设计:使用原始类型
def calculate_distance(x1, y1, x2, y2):
    return ((x2 - x1)**2 + (y2 - y1)**2)**0.5

# 好的设计:使用值对象
class Point:
    def __init__(self, x, y):
        self.x = x
        123  # Bug in original
        self.y = y
    
    def distance_to(self, other):
        return ((other.x - self.x)**2 + (other.y - self.y)**2)**0.5

def calculate_distance(p1, p2):
    return p1.distance_to(p2)

3. 聚合的设计原则

# 聚合设计:银行账户聚合
class BankAccount:
    def __init__(self, account_id, owner_name, initial_balance=0):
        self.account_id = account_id
        self.owner_name =123  # Bug in original
        self.balance = initial_balance
        self.holds = []
        self.status = "ACTIVE"
    
    def withdraw(self, amount):
        if amount <= 0:
            raise ValueError("Invalid amount")
        if self.balance < amount:
            raise ValueError("Insufficient funds")
        if self.status != "ACTIVE":
            raise ValueError("Account not active")
        
        self.balance -= amount
        return Transaction(self.account_id, "WITHDRAW", amount)
    
    def place_hold(self, amount):
        if amount <= 0:
            raise ValueError("Invalid amount")
        if self.balance < amount:
            raise ValueError("Insufficient funds")
        
        hold = Hold(amount, datetime.now())
        self.holds.append(hold)
        self.balance -= amount
    
    def release_hold(self, hold_id):
        hold = next((h for h in self.holds if h.id == hold_id), None)
        if hold:
            self.balance += hold.amount
            self.holds.remove(hold)

4. 领域服务的设计原则

# 领域服务:复杂的业务逻辑
class LoanApplicationService:
    def __init__(self, loan_repository, credit_service, notification_service):
        self.loan_repository = loan_repository
        123  # Bug in original
        self.credit_service = credit_service
        self.notification_service = notification_service
    
    def apply_for_loan(self, applicant_info, loan_amount, term):
        # 1. 创建贷款申请
        application = LoanApplication(applicant_info, loan_amount, term)
        
        # 2. 检查信用评分
        credit_score = self.credit_service.get_score(applicant_info.ssn)
        if credit_score < 600:
            application.reject("Credit score too low")
            self.loan_repository.save(application)
            self.notification_service.notify_rejection(applicant_info.email)
            return application
        
        // 3. 计算利率
        interest_rate = self._calculate_interest_rate(credit_score, loan_amount, term)
        application.set_interest_rate(interest_rate)
        
        // 4. 验证债务收入比
        dti = self._calculate_dti(applicant_info.monthly_income, loan_amount, term, interest_rate)
        if dti > 0.43:
            application.reject("DTI too high")
            self.loan_repository.save(application)
            self.notification_service.notify_rejection(applicant_info.email)
            return application
        
        // 5. 批准贷款
        application.approve()
        self.loan_repository.save(application)
        self.notification_service.notify_approval(applicant_info.email)
        
        return application

5. 领域事件的设计原则

# 领域事件:事件驱动架构
class DomainEventPublisher:
    def __init__(self):
        self.subscribers = defaultdict(list)
    
    def subscribe(self, event_type, handler):
        self.subscribers[event_type].append(handler)
    
    def publish(self, event):
        event_type = type(event).__name__
        for handler in self.subscribers.get(event_type, []):
            handler(event)

# 使用示例
class OrderService:
    def __init__(self, order_repository, event_publisher):
        self.order_repository = order_repository
        self.event_publisher = event_publisher
    
    def create_order(self, customer_id, items):
        order = Order(customer_id, items)
        self.order_repository.save(order)
        
        # 发布领域事件
        event = OrderCreatedEvent(
            order_id=order.order_id,
            customer_id=customer_id,
            items=items,
            timestamp=datetime.now()
        )
        self.event_publisher.publish(event)
        return order

DDD的实现模式

1. 工厂(Factory)

class OrderFactory:
    @staticmethod
    def create_from_cart(cart, customer_id):
        if not cart.items:
            raise ValueError("Cart is empty")
        
        order = Order(customer_id)
        for item in cart.items:
            order.add_item(item.product_id, item.quantity, item.price)
        
        # 应用折扣规则
        if cart.total_amount > 1000:
            order.apply_discount(0.1)
        
        return order

2. 仓储(Repository)

from abc import ABC, abstractmethod

class OrderRepository(ABC):
    @abstractmethod
    def save(self, order):
        pass
    
    @abstractmethod
    def find_by_id(self, order_id):
        pass
    
    @abstractmethod
 123  # Bug in original
    def find_by_customer(self, customer_id):
        pass

class SQLOrderRepository(OrderRepository):
    def __init__(self, db_connection):
        self.db = db_connection
    
    def save(self, order):
        # 将聚合根转换为数据库模型
        order_data = {
            "order_id": str(order.order_id),
            "customer_id": order.customer_id,
            "status": order.status,
            "total_amount": order.total_amount,
            "items": json.dumps([{
                "product_id": item.product_id,
                "quantity": item.quantity,
                "price": item.price
            } for item in order.items])
        }
        self.db.execute(
            "INSERT INTO orders (order_id, customer_id, status, total_amount, items) VALUES (?, ?, ?, ?, ?)",
            (order_data["order_id"], order_data["customer_id"], order_data["status"], order_data["total_amount"], order_data["items"])
        )
    
    def find_by_id(self, order_id):
        row = self.db.execute(
            "SELECT * FROM orders WHERE order_id = ?", (str(order_id),)
        ).fetchone()
        if not row:
            return None
        
        # 从数据库模型重构聚合
        order = Order(customer_id=row["customer_id"])
        order.order_id = UUID(row["order_id"])
        order.status = row["status"]
        order.total_amount = row["total_amount"]
        
        items = json.loads(row["items"])
        for item_data in items:
            item = OrderItem(
                product_id=item_data["product_id"],
                quantity=item_data["quantity"],
                price=item_data["price"]
            )
            order.items.append(item)
        
        return order

3. 防腐层(Anti-Corruption Layer)

class ExternalPaymentSystemAdapter:
    """
    防腐层:隔离外部支付系统的复杂性
    """
    def __init__(self, external_client):
        self.client = external_client
    
    def process_payment(self, payment_info):
        try:
            # 转换内部模型到外部模型
            external_request = {
                "merchant_id": self.client.merchant_id,
                "amount": payment_info.amount * 100,  # 转换为分
                "currency": payment_info.currency,
                "order_id": payment_info.order_id,
                "card_number": payment_info.card_number,
                "expiry_month": payment_info.expiry_month,
                "expiry_year": payment_info.expiry_year,
                "cvv": payment_info.cvv
            }
            
            # 调用外部系统
            external_response = self.client.charge(external_request)
            
            # 转换外部模型回内部模型
            internal_result = PaymentResult(
                success=external_response["status"] == "success",
                transaction_id=external_response.get("transaction_id"),
                message=external_response.get("message", ""),
                amount=external_response.get("amount", 0) / 100
            )
            
            return internal_result
            
        except ExternalSystemError as e:
            # 将外部异常转换为领域异常
            raise PaymentProcessingError(f"Payment failed: {str(e)}")

DDD与微服务架构

DDD与微服务架构有着天然的契合度。限界上下文通常可以映射到微服务边界:

1. 服务划分

# 微服务边界示例
# 服务1:用户服务
class UserService:
    def register_user(self, user_info):
        # 用户注册逻辑
        pass
    
    def authenticate(self, credentials):
        # 认证逻辑
        pass

# 服务2:商品服务
class ProductService:
    def get_product(self, product_id):
        # 商品查询逻辑
        pass
    
    def update_stock(self, product_id, quantity):
        # 库存更新逻辑
        pass

# 服务3:订单服务
class OrderService:
    def create_order(self, customer_id, items):
        # 订单创建逻辑
        # 需要调用商品服务验证库存
        # 需要调用用户服务验证用户
        pass

2. 服务间通信

class OrderService:
    def __init__(self, product_client, user_client, event_publisher):
        self.product_client = product_client  # HTTP/RPC调用商品服务
        self.user_client = user_client        # HTTP/RPC调用用户服务
        self.event_publisher = event_publisher
    
    def create_order(self, customer_id, items):
        # 1. 验证用户
        user = self.user_client.get_user(customer_id)
        if not user or user.status != "ACTIVE":
            raise ValueError("Invalid user")
        
        # 2. 验证商品和库存
        total_amount = 0
        for item in items:
            product = self.product_client.get_product(item["product_id"])
            if not product:
                raise ValueError(f"Product {item['product_id']} not found")
            
            # 检查库存
            if product.stock < item["quantity"]:
                raise ValueError(f"Insufficient stock for {item['product_id']}")
            
            total_amount += product.price * item["quantity"]
        
        # 3. 创建订单
        order = Order(customer_id, items, total_amount)
        
        # 4. 扣减库存(通过事件)
        event = OrderCreatedEvent(order.order_id, items)
        self.event_publisher.publish(event)
        
        return order

DDD实践中的挑战与解决方案

1. 学习曲线陡峭

挑战:DDD概念复杂,团队需要时间掌握。

解决方案

  • 从简单项目开始,逐步引入DDD
  • 组织DDD工作坊,让团队快速理解核心概念
  • 使用示例代码和案例研究

2. 过度设计

挑战:容易陷入过度工程化的陷阱。

解决方案

  • 遵循”简单设计”原则
  • 只在真正复杂的业务领域使用DDD
  • 优先考虑业务价值而非技术完美

3. 团队协作

挑战:需要开发人员和领域专家紧密合作。

解决方案

  • 建立定期沟通机制
  • 使用通用语言作为沟通桥梁
  • 让领域专家参与代码审查

4. 数据库设计

挑战:DDD强调领域模型,但数据库设计可能不同。

解决方案

  • 使用Repository模式隔离持久化细节
  • 考虑使用ORM工具(如SQLAlchemy)映射领域模型
  • 接受模型和数据库结构的差异

DDD的适用场景

适合使用DDD的场景:

  1. 复杂业务逻辑:业务规则多变且复杂
  2. 长期维护:需要长期演进和维护的系统
  3. 团队协作:需要业务和技术团队紧密合作
  4. 微服务架构:需要清晰的服务边界

不适合使用DDD的场景:

  1. 简单CRUD应用:业务逻辑简单
  2. 原型开发:快速验证想法阶段
  3. 短期项目:一次性或短期使用的系统
  4. 性能敏感:对性能要求极高,需要精细控制

实际案例:电商订单系统

让我们看一个完整的电商订单系统示例:

from abc import ABC, abstractmethod
from datetime import datetime
from typing import List, Optional
from uuid import UUID, uuid4
from enum import Enum

# 领域事件
class OrderCreatedEvent:
    def __init__(self, order_id, customer_id, items, total_amount):
        self.order_id = order_id
        self.customer_id = customer_id
        self.items = items
        self.total_amount = total_amount
        self.timestamp = datetime.now()

class OrderConfirmedEvent:
    def __init__(self, order_id, total_amount):
        self.order_id = order_id
        self.total_amount = total_amount
        self.timestamp = datetime.now()

class OrderCancelledEvent:
    def __init__(self, order_id, reason):
        self.order_id = order_id
        self.reason = reason
        self.timestamp = datetime.now()

# 值对象
class Address:
    def __init__(self, street, city, state, zip_code, country):
        self.street = street
        self.city = city
        self.state = state
        self.zip_code = zip_code
        self.country = country
    
    def __eq__(self, other):
        return (isinstance(other, Address) and
                self.street == other.street and
                self.city == other.city and
                self.state == other.state and
                self.zip_code == other.zip_code and
                self.country == other.country)
    
    def __str__(self):
        return f"{self.street}, {self.city}, {self.state} {self.zip_code}, {self.country}"

class Money:
    def __init__(self, amount, currency="USD"):
        if amount < 0:
            raise ValueError("Amount cannot be negative")
        self.amount = amount
        self.currency = currency
    
    def __add__(self, other):
        if self.currency != other.currency:
            raise ValueError("Currency mismatch")
        return Money(self.amount + other.amount, self.currency)
    
    def __sub__(self, other):
        if self.currency != other.currency:
            raise ValueError("Currency mismatch")
        return Money(self.amount - other.amount, self.currency)
    
    def __mul__(self, multiplier):
        return Money(self.amount * multiplier, self.currency)
    
    def __eq__(self, other):
        return (isinstance(other, Money) and
                self.amount == other.amount and
                self.currency == other.currency)
    
    def __str__(self):
        return f"${self.amount:.2f} {self.currency}"

# 实体
class OrderItem:
    def __init__(self, product_id: UUID, product_name: str, quantity: int, unit_price: Money):
        self.product_id = product_id
        self.product_name = product_name
        self.quantity = quantity
        self.unit_price = unit_price
    
    def subtotal(self) -> Money:
        return self.unit_price * self.quantity
    
    def __eq__(self, other):
        return (isinstance(other, OrderItem) and
                self.product_id == other.product_id)

# 聚合根
class OrderStatus(Enum):
    PENDING = "PENDING"
    CONFIRMED = "CONFIRMED"
    PAID = "PAID"
    SHIPPED = "SHIPPED"
    DELIVERED = "DELIVERED"
    CANCELLED = "CANCELLED"

class Order:
    def __init__(self, customer_id: UUID, shipping_address: Address):
        self.order_id = uuid4()
        self.customer_id = customer_id
        self.shipping_address = shipping_address
        self.items: List[OrderItem] = []
        self.status = OrderStatus.PENDING
        self.subtotal = Money(0)
        self.tax = Money(0)
        self.total = Money(0)
        self.created_at = datetime.now()
        self.updated_at = datetime.now()
    
    def add_item(self, product_id: UUID, product_name: str, quantity: int, unit_price: Money):
        if self.status != OrderStatus.PENDING:
            raise ValueError("Cannot modify confirmed order")
        
        if quantity <= 0:
            raise ValueError("Quantity must be positive")
        
        # 检查是否已存在相同商品
        existing_item = next((item for item in self.items if item.product_id == product_id), None)
        if existing_item:
            existing_item.quantity += quantity
        else:
            self.items.append(OrderItem(product_id, product_name, quantity, unit_price))
        
        self._recalculate_totals()
    
    def remove_item(self, product_id: UUID):
        if self.status != OrderStatus.PENDING:
            raise ValueError("Cannot modify confirmed order")
        
        self.items = [item for item in self.items if item.product_id != product_id]
        self._recalculate_totals()
    
    def _recalculate_totals(self):
        self.subtotal = Money(sum(item.subtotal().amount for item in self.items))
        # 简单的税率计算(实际应用中可能更复杂)
        self.tax = self.subtotal * 0.08  # 8% tax
        self.total = self.subtotal + self.tax
    
    def confirm(self) -> OrderConfirmedEvent:
        if self.status != OrderStatus.PENDING:
            raise ValueError("Order can only be confirmed from PENDING status")
        if not self.items:
            raise ValueError("Cannot confirm empty order")
        
        self.status = OrderStatus.CONFIRMED
        self.updated_at = datetime.now()
        
        return OrderConfirmedEvent(self.order_id, self.total)
    
    def cancel(self, reason: str) -> OrderCancelledEvent:
        if self.status not in [OrderStatus.PENDING, OrderStatus.CONFIRMED]:
            raise ValueError("Cannot cancel order in current status")
        
        self.status = OrderStatus.CANCELLED
        self.updated_at = datetime.now()
        
        return OrderCancelledEvent(self.order_id, reason)
    
    def pay(self):
        if self.status != OrderStatus.CONFIRMED:
            raise ValueError("Order must be confirmed before payment")
        self.status = OrderStatus.PAID
        self.updated_at = datetime.now()
    
    def ship(self):
        if self.status != OrderStatus.PAID:
            raise ValueError("Order must be paid before shipping")
        self.status = OrderStatus.SHIPPED
        self.updated_at = datetime.now()
    
    def deliver(self):
        if self.status != OrderStatus.SHIPPED:
            raise ValueError("Order must be shipped before delivery")
        self.status = OrderStatus.DELIVERED
        self.updated_at = datetime.now()

# 领域服务
class OrderDomainService:
    def __init__(self, order_repository, inventory_service, event_publisher):
        self.order_repository = order_repository
        self.inventory_service = inventory_service
        self.event_publisher = event_publisher
    
    def create_order_from_cart(self, customer_id: UUID, cart_items: List[dict], shipping_address: Address) -> Order:
        # 1. 验证库存
        for item in cart_items:
            available = self.inventory_service.check_stock(item["product_id"], item["quantity"])
            if not available:
                raise ValueError(f"Insufficient stock for {item['product_name']}")
        
        # 2. 创建订单
        order = Order(customer_id, shipping_address)
        
        for item in cart_items:
            # 获取商品信息(可能需要调用商品服务)
            product_info = self.inventory_service.get_product_info(item["product_id"])
            order.add_item(
                product_id=item["product_id"],
                product_name=product_info.name,
                quantity=item["quantity"],
                unit_price=Money(product_info.price)
            )
        
        # 3. 保存订单
        self.order_repository.save(order)
        
        # 4. 发布事件
        event = OrderCreatedEvent(
            order_id=order.order_id,
            customer_id=customer_id,
            items=[{
                "product_id": str(item.product_id),
                "name": item.product_name,
                "quantity": item.quantity,
                "price": str(item.unit_price)
            } for item in order.items],
            total_amount=str(order.total)
        )
        self.event_publisher.publish(event)
        
        return order
    
    def confirm_order(self, order_id: UUID) -> Order:
        order = self.order_repository.find_by_id(order_id)
        if not order:
            raise ValueError("Order not found")
        
        event = order.confirm()
        self.order_repository.save(order)
        self.event_publisher.publish(event)
        
        return order
    
    def cancel_order(self, order_id: UUID, reason: str) -> Order:
        order = self.order_repository.find_by_id(order_id)
        if not order:
            raise ValueError("Order not found")
        
        event = order.cancel(reason)
        self.order_repository.save(order)
        self.event_publisher.publish(event)
        
        return order

# 仓储接口
class OrderRepository(ABC):
    @abstractmethod
    def save(self, order: Order) -> None:
        pass
    
    @abstractmethod
    def find_by_id(self, order_id: UUID) -> Optional[Order]:
        pass
    
    @abstractmethod
    def find_by_customer(self, customer_id: UUID) -> List[Order]:
        pass

# 仓储实现(SQLAlchemy示例)
from sqlalchemy import Column, String, Integer, DateTime, JSON
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class OrderModel(Base):
    __tablename__ = "orders"
    
    order_id = Column(String, primary_key=True)
    customer_id = Column(String, nullable=False)
    status = Column(String, nullable=False)
    shipping_address = Column(JSON, nullable=False)
    items = Column(JSON, nullable=False)
    subtotal = Column(String, nullable=False)
    tax = Column(String, nullable=False)
    total = Column(String, nullable=False)
    created_at = Column(DateTime, nullable=False)
    updated_at = Column(DateTime, nullable=False)

class SQLOrderRepository(OrderRepository):
    def __init__(self, session_factory):
        self.session_factory = session_factory
    
    def save(self, order: Order) -> None:
        session = self.session_factory()
        try:
            # 将领域模型转换为持久化模型
            model = OrderModel(
                order_id=str(order.order_id),
                customer_id=str(order.customer_id),
                status=order.status.value,
                shipping_address={
                    "street": order.shipping_address.street,
                    "city": order.shipping_address.city,
                    "state": order.shipping_address.state,
                    "zip_code": order.shipping_address.zip_code,
                    "country": order.shipping_address.country
                },
                items=[{
                    "product_id": str(item.product_id),
                    "product_name": item.product_name,
                    "quantity": item.quantity,
                    "unit_price": str(item.unit_price)
                } for item in order.items],
                subtotal=str(order.subtotal),
                tax=str(order.tax),
                total=str(order.total),
                created_at=order.created_at,
                updated_at=order.updated_at
            )
            
            session.merge(model)
            session.commit()
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def find_by_id(self, order_id: UUID) -> Optional[Order]:
        session = self.session_factory()
        try:
            model = session.query(OrderModel).filter_by(order_id=str(order_id)).first()
            if not model:
                return None
            
            return self._to_domain_model(model)
        finally:
            session.close()
    
    def find_by_customer(self, customer_id: UUID) -> List[Order]:
        session = self.session_factory()
        try:
            models = session.query(OrderModel).filter_by(customer_id=str(customer_id)).all()
            return [self._to_domain_model(model) for model in models]
        finally:
            session.close()
    
    def _to_domain_model(self, model: OrderModel) -> Order:
        # 从持久化模型重构领域模型
        shipping_address = Address(
            street=model.shipping_address["street"],
            city=model.shipping_address["city"],
            state=model.shipping_address["state"],
            zip_code=model.shipping_address["zip_code"],
            country=model.shipping_address["country"]
        )
        
        order = Order(
            customer_id=UUID(model.customer_id),
            shipping_address=shipping_address
        )
        
        # 恢复订单ID
        order.order_id = UUID(model.order_id)
        order.status = OrderStatus(model.status)
        order.created_at = model.created_at
        order.updated_at = model.updated_at
        
        # 恢复订单项
        for item_data in model.items:
            item = OrderItem(
                product_id=UUID(item_data["product_id"]),
                product_name=item_data["product_name"],
                quantity=item_data["quantity"],
                unit_price=Money.from_string(item_data["unit_price"])
            )
            order.items.append(item)
        
        # 恢复金额
        order.subtotal = Money.from_string(model.subtotal)
        order.tax = Money.from_string(model.tax)
        order.total = Money.from_string(model.total)
        
        return order

# 事件处理器
class InventoryEventHandler:
    def __init__(self, inventory_service):
        self.inventory_service = inventory_service
    
    def handle_order_created(self, event: OrderCreatedEvent):
        # 扣减库存
        for item in event.items:
            self.inventory_service.decrease_stock(
                UUID(item["product_id"]),
                item["quantity"]
            )

class NotificationEventHandler:
    def __init__(self, notification_service):
        self.notification_service = notification_service
    
    def handle_order_confirmed(self, event: OrderConfirmedEvent):
        # 发送确认邮件
        self.notification_service.send_order_confirmation(
            event.order_id,
            event.total_amount
        )
    
    def handle_order_cancelled(self, event: OrderCancelledEvent):
        # 发送取消通知
        self.notification_service.send_order_cancellation(
            event.order_id,
            event.reason
        )

# 使用示例
def main():
    # 初始化依赖
    event_publisher = DomainEventPublisher()
    order_repository = SQLOrderRepository(session_factory)
    inventory_service = InventoryService()
    notification_service = NotificationService()
    
    # 注册事件处理器
    inventory_handler = InventoryEventHandler(inventory_service)
    notification_handler = NotificationEventHandler(notification_service)
    
    event_publisher.subscribe("OrderCreatedEvent", inventory_handler.handle_order_created)
    event_publisher.subscribe("OrderConfirmedEvent", notification_handler.handle_order_confirmed)
    event_publisher.subscribe("OrderCancelledEvent", notification_handler.handle_order_cancelled)
    
    # 创建领域服务
    order_service = OrderDomainService(
        order_repository,
        inventory_service,
        event_publisher
    )
    
    # 创建订单
    try:
        customer_id = uuid4()
        shipping_address = Address(
            street="123 Main St",
            city="New York",
            state="NY",
            zip_code="10001",
            country="USA"
        )
        
        cart_items = [
            {"product_id": uuid4(), "product_name": "Laptop", "quantity": 1},
            {"product_id": uuid4(), "product_name": "Mouse", "quantity": 2}
        ]
        
        order = order_service.create_order_from_cart(customer_id, cart_items, shipping_address)
        print(f"Order created: {order.order_id}")
        
        # 确认订单
        order_service.confirm_order(order.order_id)
        print(f"Order confirmed: {order.order_id}")
        
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()

总结

领域驱动设计(DDD)是一种强大的软件设计方法论,它通过将焦点放在业务领域上,帮助我们构建更灵活、更易维护的软件系统。虽然DDD有一定的学习曲线,但其带来的好处是显著的:

  1. 更好的业务对齐:软件模型直接反映业务概念
  2. 提高可维护性:清晰的边界和职责分离
  3. 促进团队协作:统一语言减少沟通成本
  4. 支持复杂系统:有效管理复杂性

在实际应用中,应该根据项目的具体需求和团队的成熟度来决定是否采用DDD,以及采用DDD的哪些部分。记住,DDD不是银弹,而是一种需要根据具体情况灵活应用的工具。

通过持续学习和实践,团队可以逐步掌握DDD的精髓,构建出更加健壮和可持续的软件系统。