






















首先要明确核心定位:MVC 是「架构分层模式」,聚焦代码的职责划分;DDD 是「领域建模方法论」,聚焦业务逻辑的抽象与落地,二者并非对立关系(DDD 可基于 MVC 分层实现),但适用场景和设计目标差异显著。
| 模式 | 核心定义 |
|---|---|
| MVC | Model(数据模型)+ View(视图)+ Controller(控制器),将「数据、展示、交互」分离,解决界面与业务代码耦合问题,是前端/后端通用的分层思想。 |
| DDD | 围绕「业务领域」建模,通过限界上下文、聚合根、领域服务、值对象等概念,将复杂业务逻辑抽象为领域模型,聚焦「业务语义」而非技术分层。 |
| 维度 | MVC 模式 | DDD 模式 |
|---|---|---|
| 优势 | - 轻量简单,学习成本低,快速上手; - 适配简单业务(如 CURD 系统、展示型网站); - 开发效率高,适合快速交付的小型项目。 |
- 适配复杂业务(如金融、电商、物流核心系统),能清晰抽象业务规则; - 领域模型与业务语言一致,降低沟通成本(开发/产品/业务方对齐); - 高内聚低耦合,便于业务扩展(如新增业务规则仅修改领域层)。 |
| 劣势 | - 业务逻辑易散落在 Controller/Model 中,复杂业务下代码混乱(「贫血模型」问题); - 缺乏业务边界,系统扩张后难以维护; - 仅解决技术分层,未解决业务抽象问题。 |
- 学习成本高(需理解限界上下文、聚合根等核心概念); - 开发周期长,小型项目使用会「过度设计」; - 对团队要求高(需业务+技术双精通)。 |
| 维度 | MVC 模式 | DDD 模式 |
|---|---|---|
| 优势 | - 结构清晰,新手易理解(控制器处理请求,模型处理数据,视图展示); - 技术分层明确,前端/后端分工清晰。 |
- 业务逻辑集中在「领域层」,技术细节(如数据库、接口)隔离在「基础设施层」; - 限界上下文划分业务边界,避免系统耦合; - 领域模型稳定,技术层可灵活替换(如换数据库、换框架不影响业务逻辑)。 |
| 劣势 | - 复杂业务下,Controller 会变成「万能层」,既处理请求又写业务逻辑,代码臃肿; - Model 常沦为「数据载体」(贫血模型),无业务行为; - 需求变更时,需修改多个层的代码,易出bug。 |
- 结构复杂,多分层(领域层、应用层、基础设施层、接口层),新手难上手; - 模型设计不当会导致过度抽象,反而增加维护成本; - 小需求变更可能需要修改领域模型,调整成本高。 |
| 维度 | MVC 模式 | DDD 模式 |
|---|---|---|
| 优势 | - 技术导向,团队只需达成「分层共识」,无需深入理解业务; - 适合纯技术团队(业务逻辑简单)。 |
- 领域模型基于「通用语言(Ubiquitous Language)」,开发、产品、业务方用同一套术语沟通,减少歧义; - 限界上下文划分团队职责,多团队并行开发不冲突。 |
| 劣势 | - 技术语言与业务语言脱节,开发需频繁翻译产品需求,易理解偏差; - 复杂业务下,团队协作易出现「重复造轮子」(不同人实现同一业务逻辑)。 |
- 要求团队深度参与业务梳理,纯技术型团队难以落地; - 通用语言的建立需要反复对齐,初期沟通成本高。 |
| 维度 | MVC 模式 | DDD 模式 |
|---|---|---|
| 优势 | - 技术层扩展简单(如新增接口只需加 Controller,新增页面只需加 View); - 适合快速迭代的轻量需求。 |
- 领域服务/值对象可跨上下文复用,业务逻辑复用性高; - 限界上下文可独立部署、扩展,支持微服务拆分(DDD 是微服务设计的核心方法论); - 新增业务场景只需基于现有领域模型扩展,无需重构整体。 |
| 劣势 | - 业务逻辑复用难(散落在各层),新增场景易重复写代码; - 系统扩张后难以拆分微服务(无业务边界); - 技术耦合严重,重构成本高。 |
- 初期扩展慢(需先设计领域模型); - 微服务拆分依赖上下文设计,设计不当会导致拆分失败; - 过度抽象可能导致复用性降低(模型与业务绑定过紧)。 |
| 模式 | 典型场景 |
|---|---|
| MVC | - 企业官网、博客、展示型小程序; - 简单的内部管理系统(如考勤、审批); - 快速原型开发、短期项目。 |
| DDD | - 电商核心系统(订单、支付、库存); - 金融系统(风控、交易、账务); - 物流系统(仓储、配送、路径规划); - 长期维护、需频繁迭代的复杂业务系统。 |
DDD 并非替代 MVC,而是在 MVC 基础上强化「业务层」设计,典型分层结构:
├── 接口层(Controller):对应 MVC 的 Controller,处理请求/响应
├── 应用层(Application):协调领域层执行,不包含核心业务逻辑
├── 领域层(Domain):核心!包含聚合根、值对象、领域服务,实现业务规则
├── 基础设施层(Infrastructure):对应 MVC 的 Model,处理数据库、缓存等技术细节
└── 视图层(View):对应 MVC 的 View,展示数据
MVC 是「技术分层框架」,DDD 是「业务建模方法论」,二者结合的核心是:将 DDD 的领域模型作为 MVC 的核心,重构 MVC 各层的职责,让业务逻辑聚焦在领域层,而非散落在 Controller/Model 中。
传统 MVC 的「Model」常沦为“数据载体(贫血模型)”,结合 DDD 后需拆分分层,让各层职责更清晰:
| 传统 MVC 层 | DDD 分层 | 核心职责 |
|---|---|---|
| Controller | 接口层(API) | 仅处理 HTTP 请求/响应、参数校验、权限控制,不包含任何业务逻辑 |
| Model | 1. 领域层(核心) 2. 应用层 3. 基础设施层 |
1. 领域层:聚合根、值对象、领域服务,实现核心业务规则; 2. 应用层:协调领域层执行,编排业务流程; 3. 基础设施层:数据持久化(数据库操作)、第三方接口调用 |
| View | 视图层 | 展示数据(前后端分离场景下可省略,仅返回 JSON) |
以「电商订单创建」场景为例(Python + Flask 实现,其他语言思路一致),完整展示各层代码和职责。
领域层是核心,包含聚合根、值对象、领域服务,聚焦业务规则,不依赖任何技术框架。
# domain/order.py - 领域层(核心业务逻辑)
from dataclasses import dataclass
from datetime import datetime
from typing import List
# 1. 值对象:无唯一标识,不可变(如地址、金额)
@dataclass(frozen=True) # frozen=True 保证不可变
class Address:
province: str
city: str
detail: str
receiver: str
phone: str
# 2. 聚合根:有唯一标识,包含业务行为(订单是聚合根,包含订单项)
class OrderItem:
def __init__(self, product_id: str, quantity: int, price: float):
self.product_id = product_id
self.quantity = quantity
self.price = price
self.validate() # 内置业务规则校验
def validate(self):
if self.quantity <= 0:
raise ValueError("订单项数量必须大于0")
if self.price < 0:
raise ValueError("商品价格不能为负数")
@property
def total_price(self):
return self.quantity * self.price # 业务计算逻辑
class Order:
def __init__(self, user_id: str, items: List[OrderItem], address: Address):
self.order_id = None # 持久化后生成
self.user_id = user_id
self.items = items
self.address = address
self.status = "pending" # 初始状态
self.create_time = datetime.now()
self.total_amount = self.calculate_total() # 核心业务逻辑
# 核心业务行为:计算订单总价
def calculate_total(self) -> float:
return sum(item.total_price for item in self.items)
# 核心业务规则:订单提交校验
def validate_submit(self):
if not self.items:
raise ValueError("订单不能为空")
if self.total_amount <= 0:
raise ValueError("订单金额必须大于0")
# 核心业务行为:更新订单状态
def confirm_payment(self):
if self.status != "pending":
raise ValueError("仅待支付订单可确认支付")
self.status = "paid"
# 3. 领域服务:处理跨聚合根的业务逻辑(单个聚合根能处理的逻辑不放在这里)
class OrderDomainService:
@staticmethod
def check_stock(order: Order, stock_repository) -> bool:
"""检查所有订单项的库存(跨订单和商品两个聚合根)"""
for item in order.items:
stock = stock_repository.get_stock(item.product_id)
if stock < item.quantity:
return False
return True
应用层是「业务流程编排器」,负责调用领域层的方法、协调多个领域对象/基础设施服务,不包含核心业务规则(核心规则全在领域层)。
# application/order_service.py - 应用层
from domain.order import Order, OrderItem, Address, OrderDomainService
from infrastructure.repositories import OrderRepository, StockRepository
class OrderApplicationService:
def __init__(self):
self.order_repo = OrderRepository() # 基础设施层:数据持久化
self.stock_repo = StockRepository() # 基础设施层:库存查询
def create_order(self, user_id: str, items_data: list, address_data: dict) -> dict:
"""创建订单的业务流程编排(应用层逻辑)"""
# 1. 组装领域对象(值对象+聚合根)
address = Address(**address_data)
order_items = [OrderItem(**item) for item in items_data]
order = Order(user_id, order_items, address)
# 2. 调用领域层规则校验
order.validate_submit()
# 3. 调用领域服务(跨聚合根逻辑)
if not OrderDomainService.check_stock(order, self.stock_repo):
raise ValueError("部分商品库存不足")
# 4. 持久化(调用基础设施层)
order.order_id = self.order_repo.generate_order_id()
self.order_repo.save(order)
# 5. 返回结果(仅数据,无业务逻辑)
return {
"order_id": order.order_id,
"total_amount": order.total_amount,
"status": order.status
}
基础设施层负责「技术细节」,如数据库操作、缓存、第三方接口调用,为领域层提供持久化能力,且依赖倒置(领域层不依赖基础设施层,而是通过接口/抽象依赖)。
# infrastructure/repositories.py - 基础设施层
import uuid
from domain.order import Order
class OrderRepository:
"""订单仓储:处理订单的数据库操作"""
def __init__(self):
# 模拟数据库(实际项目中替换为 SQLAlchemy/ORM 等)
self.db = {}
def generate_order_id(self) -> str:
return str(uuid.uuid4())
def save(self, order: Order):
self.db[order.order_id] = {
"order_id": order.order_id,
"user_id": order.user_id,
"items": [{"product_id": item.product_id, "quantity": item.quantity, "price": item.price} for item in order.items],
"address": {
"province": order.address.province,
"city": order.address.city,
"detail": order.address.detail,
"receiver": order.address.receiver,
"phone": order.address.phone
},
"status": order.status,
"total_amount": order.total_amount,
"create_time": order.create_time
}
def get_by_id(self, order_id: str) -> Order:
"""将数据库数据转换为领域对象(反序列化)"""
data = self.db.get(order_id)
if not data:
raise ValueError("订单不存在")
address = Address(
province=data["address"]["province"],
city=data["address"]["city"],
detail=data["address"]["detail"],
receiver=data["address"]["receiver"],
phone=data["address"]["phone"]
)
items = [OrderItem(**item) for item in data["items"]]
order = Order(data["user_id"], items, address)
order.order_id = data["order_id"]
order.status = data["status"]
return order
class StockRepository:
"""库存仓储:模拟第三方库存查询"""
def __init__(self):
self.stock_db = {"prod_001": 100, "prod_002": 50}
def get_stock(self, product_id: str) -> int:
return self.stock_db.get(product_id, 0)
传统 MVC 的 Controller 常写满业务逻辑,结合 DDD 后需“瘦身”,仅做参数校验、调用应用层、返回响应。
# controllers/order_controller.py - 接口层(MVC 的 Controller)
from flask import Flask, request, jsonify
from application.order_service import OrderApplicationService
app = Flask(__name__)
order_app_service = OrderApplicationService()
@app.route("/api/orders", methods=["POST"])
def create_order():
"""仅处理请求:参数校验 → 调用应用层 → 返回响应"""
# 1. 参数校验(仅技术层面,业务校验在领域层)
data = request.json
required_fields = ["user_id", "items", "address"]
for field in required_fields:
if field not in data:
return jsonify({"code": 400, "msg": f"缺少参数:{field}"}), 400
# 2. 调用应用层(核心:不写任何业务逻辑)
try:
result = order_app_service.create_order(
user_id=data["user_id"],
items_data=data["items"],
address_data=data["address"]
)
return jsonify({"code": 200, "msg": "订单创建成功", "data": result}), 200
except ValueError as e:
return jsonify({"code": 400, "msg": str(e)}), 400
if __name__ == "__main__":
app.run(debug=True)
领域层“纯业务”:不依赖任何技术框架
依赖倒置:领域层不依赖基础设施层
# domain/repositories.py - 领域层定义接口
from abc import ABC, abstractmethod
from domain.order import Order
class OrderRepositoryInterface(ABC):
@abstractmethod
def save(self, order: Order):
pass
# infrastructure/repositories.py - 基础设施层实现接口
class OrderRepository(OrderRepositoryInterface):
def save(self, order: Order):
# 数据库操作
pass
应用层“只协调,不决策”
Controller“只传参,不处理”
# 发送 POST 请求到 http://127.0.0.1:5000/api/orders
# 请求体
{
"user_id": "user_001",
"items": [
{"product_id": "prod_001", "quantity": 2, "price": 100},
{"product_id": "prod_002", "quantity": 1, "price": 50}
],
"address": {
"province": "北京",
"city": "北京市",
"detail": "XX小区XX号楼",
"receiver": "张三",
"phone": "13800138000"
}
}
# 响应(成功)
{
"code": 200,
"msg": "订单创建成功",
"data": {
"order_id": "xxx-xxx-xxx",
"total_amount": 250.0,
"status": "pending"
}
}
在 MVC 中定义 DDD 领域模型的核心是:把传统 MVC 中“仅存数据的贫血 Model”升级为“包含业务行为的充血领域模型”,让领域模型成为业务规则的唯一载体,而非单纯的数据结构体。以下是具体的定义方法、原则和实操案例。
传统 MVC 的 Model 通常是「贫血模型」(只有属性,无业务方法),而 DDD 领域模型是「充血模型」,需满足 3 个核心特征:
| 特征 | 传统 MVC Model | DDD 领域模型 |
|---|---|---|
| 核心职责 | 存储数据、简单的数据校验 | 封装业务规则、实现业务行为 |
| 依赖关系 | 依赖数据库/ORM 框架 | 不依赖任何技术框架(纯业务) |
| 设计依据 | 数据库表结构 | 业务语义(通用语言) |
以「电商退款」场景为例(Python 实现,Java/C# 思路一致),完整演示如何定义领域模型。
先和产品/业务方对齐术语(通用语言),拆分出核心领域对象:
Refund(退款单,有唯一标识,是核心对象);RefundAmount(退款金额,无唯一标识、不可变);RefundDomainService(处理跨聚合根的逻辑,如“退款金额校验”)。值对象是无唯一标识、不可变的业务概念(如金额、地址、时间范围),用于封装简单业务规则,是领域模型的基础。
# domain/value_objects.py(纯业务,无技术依赖)
from dataclasses import dataclass
# 退款金额值对象(不可变,内置金额校验规则)
@dataclass(frozen=True) # frozen=True 保证不可变(值对象核心特征)
class RefundAmount:
total: float # 退款总金额
refund_fee: float # 商品退款金额
freight: float # 运费退款金额
# 内置业务规则校验(值对象自身负责合法性)
def __post_init__(self):
self._validate_amount()
def _validate_amount(self):
# 业务规则1:总金额 = 商品金额 + 运费
if round(self.total, 2) != round(self.refund_fee + self.freight, 2):
raise ValueError(f"退款总金额({self.total})必须等于商品金额({self.refund_fee})+运费({self.freight})")
# 业务规则2:金额不能为负
if self.total < 0 or self.refund_fee < 0 or self.freight < 0:
raise ValueError("退款金额不能为负数")
聚合根是有唯一标识的核心领域对象,包含业务行为,是领域模型的核心。它会组合值对象/其他实体,封装核心业务规则。
# domain/aggregates.py(核心业务逻辑)
from datetime import datetime
from enum import Enum
from .value_objects import RefundAmount
# 退款状态(通用语言:和业务方对齐的状态名称)
class RefundStatus(Enum):
INIT = "待审核"
APPROVED = "审核通过"
REJECTED = "审核驳回"
REFUNDED = "已退款"
FAILED = "退款失败"
# 退款单聚合根(核心领域对象)
class Refund:
# 初始化:仅接收业务参数,不依赖任何技术组件(如ORM)
def __init__(self, order_id: str, user_id: str, amount: RefundAmount, reason: str):
self.refund_id = None # 持久化后生成(技术层负责,领域层不关心)
self.order_id = order_id
self.user_id = user_id
self.amount = amount # 组合值对象
self.reason = reason
self.status = RefundStatus.INIT # 初始状态
self.create_time = datetime.now()
self.audit_time = None
self.audit_user = None
# 业务行为1:审核退款(封装状态流转规则)
def audit(self, audit_user: str, is_approved: bool):
# 业务规则1:只有待审核的退款单可审核
if self.status != RefundStatus.INIT:
raise ValueError(f"仅待审核的退款单可审核,当前状态:{self.status.value}")
# 业务规则2:审核通过后状态改为“审核通过”,驳回则改为“审核驳回”
self.status = RefundStatus.APPROVED if is_approved else RefundStatus.REJECTED
self.audit_time = datetime.now()
self.audit_user = audit_user
# 业务行为2:执行退款(封装退款规则)
def refund(self):
# 业务规则1:只有审核通过的退款单可退款
if self.status != RefundStatus.APPROVED:
raise ValueError(f"仅审核通过的退款单可退款,当前状态:{self.status.value}")
# 业务规则2:退款后状态改为“已退款”
self.status = RefundStatus.REFUNDED
# 业务行为3:退款失败(封装失败处理规则)
def refund_failed(self, fail_reason: str):
if self.status != RefundStatus.APPROVED:
raise ValueError(f"仅审核通过的退款单可标记失败,当前状态:{self.status.value}")
self.status = RefundStatus.FAILED
self.fail_reason = fail_reason
领域服务用于处理跨聚合根/无归属的业务逻辑(单个聚合根能处理的逻辑,绝不放在领域服务中)。
# domain/services.py
from .aggregates import Refund
from infrastructure.repositories import OrderRepository
# 退款领域服务(处理跨退款单和订单的逻辑)
class RefundDomainService:
@staticmethod
def check_refund_limit(refund: Refund, order_repo: OrderRepository):
"""
业务规则:退款金额不能超过订单实付金额(跨退款单和订单两个聚合根)
"""
# 获取订单信息(通过仓储接口,领域服务不直接操作数据库)
order = order_repo.get_by_id(refund.order_id)
if not order:
raise ValueError(f"订单{refund.order_id}不存在,无法发起退款")
# 业务规则校验
if refund.amount.total > order.paid_amount:
raise ValueError(f"退款金额({refund.amount.total})不能超过订单实付金额({order.paid_amount})")
领域模型必须脱离 MVC 的技术层(如数据库、框架)独立存在,通过「仓储接口」解耦:
# 1. 领域层定义仓储接口(抽象,不依赖具体实现)
# domain/repositories.py
from abc import ABC, abstractmethod
from .aggregates import Refund
class RefundRepositoryInterface(ABC):
@abstractmethod
def save(self, refund: Refund):
pass
@abstractmethod
def get_by_id(self, refund_id: str) -> Refund:
pass
# 2. 基础设施层实现仓储接口(MVC 的 Model 层负责技术实现)
# infrastructure/repositories.py
import uuid
from domain.aggregates import Refund
from domain.repositories import RefundRepositoryInterface
class RefundRepository(RefundRepositoryInterface):
"""MVC 的 Model 层:处理数据库操作,实现领域层定义的接口"""
def __init__(self):
self.db = {} # 模拟数据库,实际替换为 ORM/MySQL 等
def save(self, refund: Refund):
# 生成退款单 ID(技术逻辑,领域层不关心)
if not refund.refund_id:
refund.refund_id = str(uuid.uuid4())
# 将领域对象转换为数据库数据(序列化)
self.db[refund.refund_id] = {
"refund_id": refund.refund_id,
"order_id": refund.order_id,
"user_id": refund.user_id,
"amount": {
"total": refund.amount.total,
"refund_fee": refund.amount.refund_fee,
"freight": refund.amount.freight
},
"reason": refund.reason,
"status": refund.status.value,
"create_time": refund.create_time,
"audit_time": refund.audit_time,
"audit_user": refund.audit_user
}
def get_by_id(self, refund_id: str) -> Refund:
"""将数据库数据转换为领域对象(反序列化)"""
data = self.db.get(refund_id)
if not data:
raise ValueError(f"退款单{refund_id}不存在")
# 重建值对象
amount = RefundAmount(
total=data["amount"]["total"],
refund_fee=data["amount"]["refund_fee"],
freight=data["amount"]["freight"]
)
# 重建聚合根
refund = Refund(
order_id=data["order_id"],
user_id=data["user_id"],
amount=amount,
reason=data["reason"]
)
refund.refund_id = data["refund_id"]
refund.status = RefundStatus(data["status"])
refund.create_time = data["create_time"]
refund.audit_time = data["audit_time"]
refund.audit_user = data["audit_user"]
return refund
MVC 的 Controller 仅做请求处理,通过应用层调用领域模型(不直接操作领域对象):
# application/services.py(应用层:协调领域层执行)
from domain.aggregates import Refund, RefundAmount
from domain.services import RefundDomainService
from infrastructure.repositories import RefundRepository, OrderRepository
class RefundApplicationService:
def __init__(self):
self.refund_repo = RefundRepository()
self.order_repo = OrderRepository()
def create_refund(self, order_id: str, user_id: str, amount_data: dict, reason: str):
# 1. 构建值对象
amount = RefundAmount(**amount_data)
# 2. 构建聚合根
refund = Refund(order_id, user_id, amount, reason)
# 3. 调用领域服务校验跨聚合根规则
RefundDomainService.check_refund_limit(refund, self.order_repo)
# 4. 持久化(调用仓储)
self.refund_repo.save(refund)
return refund
# controllers/refund_controller.py(MVC 的 Controller 层)
from flask import request, jsonify
from application.services import RefundApplicationService
app = Flask(__name__)
refund_app_service = RefundApplicationService()
@app.route("/api/refunds", methods=["POST"])
def create_refund():
"""仅处理请求/响应,不包含任何业务逻辑"""
data = request.json
# 参数校验(技术层面,业务校验在领域层)
if not all([data.get("order_id"), data.get("user_id"), data.get("amount"), data.get("reason")]):
return jsonify({"code": 400, "msg": "参数缺失"}), 400
try:
# 调用应用层,间接使用领域模型
refund = refund_app_service.create_refund(
order_id=data["order_id"],
user_id=data["user_id"],
amount_data=data["amount"],
reason=data["reason"]
)
return jsonify({
"code": 200,
"msg": "退款单创建成功",
"data": {"refund_id": refund.refund_id, "status": refund.status.value}
}), 200
except ValueError as e:
return jsonify({"code": 400, "msg": str(e)}), 400
Flask/Django/SQLAlchemy 等技术代码,只关注“业务规则是什么”,不关心“数据怎么存、请求怎么处理”;Refund、audit、RefundStatus)必须和业务方一致,避免“技术术语”与“业务术语”脱节。在 MVC 中定义 DDD 领域模型的核心是将“数据导向的贫血 Model”重构为“行为导向的充血领域模型”,并严格隔离业务逻辑与技术细节。以下是 6 个可直接落地的步骤,附清晰的职责划分和代码示例(以 Python + 电商「库存扣减」场景为例)。
核心目标:和产品、业务方统一术语,明确核心领域概念,避免“技术语言”与“业务语言”脱节。
Inventory(库存单);StockQuantity(库存数量,包含可售/锁定/预扣数量);InventoryDomainService(如校验订单库存是否足够);核心目标:用值对象封装无唯一标识、不可变的业务概念,内置基础校验规则(替代传统 Model 的简单字段校验)。
# domain/value_objects.py(领域层:仅业务逻辑)
from dataclasses import dataclass
# 库存数量值对象(不可变,封装数量校验规则)
@dataclass(frozen=True) # frozen=True 保证不可变(值对象核心)
class StockQuantity:
available: int # 可售库存
locked: int # 锁定库存(已下单未付款)
reserved: int # 预扣库存(预售)
# 初始化后自动校验业务规则
def __post_init__(self):
self._validate_quantity()
# 内置业务规则:所有库存数量不能为负
def _validate_quantity(self):
if self.available < 0 or self.locked < 0 or self.reserved < 0:
raise ValueError("库存数量不能为负数")
# 业务行为:计算总库存
@property
def total(self):
return self.available + self.locked + self.reserved
核心目标:聚合根是领域模型的核心,组合值对象/其他实体,封装所有核心业务规则(替代传统 MVC 中散落在 Controller 的业务逻辑)。
# domain/aggregates.py(领域层:核心业务逻辑)
from datetime import datetime
from .value_objects import StockQuantity
# 库存聚合根(核心领域对象)
class Inventory:
# 初始化:仅接收业务参数,不依赖ORM/数据库
def __init__(self, sku: str, quantity: StockQuantity):
self.id = None # 持久化后生成(技术层负责,领域层不关心)
self.sku = sku # 商品SKU(唯一标识)
self.quantity = quantity # 组合值对象
self.updated_time = datetime.now()
# 业务行为1:扣减可售库存(核心规则)
def deduct_available(self, deduct_num: int):
# 业务规则1:扣减数量不能为负
if deduct_num < 0:
raise ValueError("扣减数量不能为负数")
# 业务规则2:可售库存不足时禁止扣减
if self.quantity.available < deduct_num:
raise ValueError(f"SKU{self.sku}可售库存不足,当前{self.quantity.available},需扣减{deduct_num}")
# 执行扣减(生成新的不可变值对象)
new_available = self.quantity.available - deduct_num
self.quantity = StockQuantity(
available=new_available,
locked=self.quantity.locked,
reserved=self.quantity.reserved
)
self.updated_time = datetime.now()
# 业务行为2:锁定库存(下单时)
def lock_stock(self, lock_num: int):
if lock_num < 0:
raise ValueError("锁定数量不能为负数")
if self.quantity.available < lock_num:
raise ValueError(f"SKU{self.sku}可售库存不足,无法锁定{lock_num}")
# 可售库存减少,锁定库存增加
self.quantity = StockQuantity(
available=self.quantity.available - lock_num,
locked=self.quantity.locked + lock_num,
reserved=self.quantity.reserved
)
self.updated_time = datetime.now()
# 业务行为3:解锁库存(取消订单时)
def unlock_stock(self, unlock_num: int):
if unlock_num < 0:
raise ValueError("解锁数量不能为负数")
if self.quantity.locked < unlock_num:
raise ValueError(f"SKU{self.sku}锁定库存不足,无法解锁{unlock_num}")
self.quantity = StockQuantity(
available=self.quantity.available + unlock_num,
locked=self.quantity.locked - unlock_num,
reserved=self.quantity.reserved
)
self.updated_time = datetime.now()
核心目标:处理单个聚合根无法覆盖的跨领域对象逻辑(如“订单扣减库存需校验多个SKU的库存”),领域服务无状态,仅封装业务规则。
# domain/services.py(领域层:跨聚合根业务规则)
from .aggregates import Inventory
# 库存领域服务
class InventoryDomainService:
@staticmethod
def check_order_stock(order_items: list, inventory_list: list[Inventory]) -> bool:
"""
业务规则:校验订单中所有SKU的库存是否足够
- order_items:[{"sku": "prod001", "num": 2}, ...]
- inventory_list:各SKU对应的库存聚合根列表
"""
# 将库存列表转为SKU映射,方便查询
inventory_map = {inv.sku: inv for inv in inventory_list}
# 逐个校验
for item in order_items:
sku = item["sku"]
need_num = item["num"]
if sku not in inventory_map:
raise ValueError(f"SKU{sku}无库存记录")
if inventory_map[sku].quantity.available < need_num:
return False
return True
核心目标:将领域模型与 MVC 的技术层(数据库操作)解耦,领域层定义抽象仓储接口,基础设施层(原 MVC 的 Model)实现接口。
# 第一步:领域层定义仓储接口(抽象)
# domain/repositories.py
from abc import ABC, abstractmethod
from .aggregates import Inventory
class InventoryRepositoryInterface(ABC):
@abstractmethod
def save(self, inventory: Inventory):
"""保存库存聚合根"""
pass
@abstractmethod
def get_by_sku(self, sku: str) -> Inventory:
"""根据SKU查询库存聚合根"""
pass
# 第二步:基础设施层实现接口(MVC 的 Model 层)
# infrastructure/repositories.py(技术层:数据库操作)
import uuid
from domain.aggregates import Inventory
from domain.value_objects import StockQuantity
from domain.repositories import InventoryRepositoryInterface
# 模拟数据库(实际项目替换为SQLAlchemy/Django ORM)
class InventoryRepository(InventoryRepositoryInterface):
def __init__(self):
self.db = {} # 存储格式:{sku: 库存数据字典}
def save(self, inventory: Inventory):
"""将领域对象序列化为数据库数据"""
if not inventory.id:
inventory.id = str(uuid.uuid4())
# 转换值对象为字典
quantity_dict = {
"available": inventory.quantity.available,
"locked": inventory.quantity.locked,
"reserved": inventory.quantity.reserved
}
self.db[inventory.sku] = {
"id": inventory.id,
"sku": inventory.sku,
"quantity": quantity_dict,
"updated_time": inventory.updated_time
}
def get_by_sku(self, sku: str) -> Inventory:
"""将数据库数据反序列化为领域对象"""
data = self.db.get(sku)
if not data:
raise ValueError(f"SKU{sku}不存在")
# 重建值对象
quantity = StockQuantity(**data["quantity"])
# 重建聚合根
inventory = Inventory(sku=data["sku"], quantity=quantity)
inventory.id = data["id"]
inventory.updated_time = data["updated_time"]
return inventory
核心目标:让 MVC 的 Controller 仅处理请求,应用层协调领域模型执行,业务逻辑完全由领域层负责。
Controller(请求处理)→ 应用层(流程协调)→ 领域层(业务规则)→ 基础设施层(数据存储)# 1. 应用层:协调领域层执行(无核心业务逻辑)
# application/services.py
from domain.aggregates import Inventory
from domain.value_objects import StockQuantity
from domain.services import InventoryDomainService
from infrastructure.repositories import InventoryRepository
class InventoryApplicationService:
def __init__(self):
self.inv_repo = InventoryRepository()
def deduct_stock(self, sku: str, deduct_num: int):
"""扣减库存的流程编排"""
# 1. 从仓储获取领域对象
inventory = self.inv_repo.get_by_sku(sku)
# 2. 调用领域对象的业务行为(核心规则)
inventory.deduct_available(deduct_num)
# 3. 保存修改后的领域对象
self.inv_repo.save(inventory)
return inventory
def check_order_stock(self, order_items: list):
"""校验订单库存的流程编排"""
# 1. 获取所有SKU的库存领域对象
skus = [item["sku"] for item in order_items]
inventory_list = [self.inv_repo.get_by_sku(sku) for sku in skus]
# 2. 调用领域服务校验规则
return InventoryDomainService.check_order_stock(order_items, inventory_list)
# 2. MVC 的 Controller 层:仅处理请求/响应
# controllers/inventory_controller.py
from flask import request, jsonify
from application.services import InventoryApplicationService
app = Flask(__name__)
inv_app_service = InventoryApplicationService()
@app.route("/api/inventory/deduct", methods=["POST"])
def deduct_stock():
"""仅处理请求参数和响应,无任何业务逻辑"""
data = request.json
# 技术层面的参数校验
if not all([data.get("sku"), data.get("deduct_num")]):
return jsonify({"code": 400, "msg": "缺少SKU或扣减数量"}), 400
try:
# 调用应用层,间接使用领域模型
inventory = inv_app_service.deduct_stock(
sku=data["sku"],
deduct_num=data["deduct_num"]
)
return jsonify({
"code": 200,
"msg": "库存扣减成功",
"data": {
"sku": inventory.sku,
"available_stock": inventory.quantity.available
}
}), 200
except ValueError as e:
return jsonify({"code": 400, "msg": str(e)}), 400
在 MVC 中定义领域模型的核心步骤可总结为 3 个核心阶段 + 3 个落地动作:
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。