title: "12 深层模型与重构"
学习目标
- 理解"浅层模型 vs 深层模型"的区别:浅层是"数据结构+CRUD",深层是"业务概念+规则"
- 能识别"隐含概念(Implicit Concept)",并通过重构显性化
- 掌握从浅层模型到深层模型的演进路径:识别 → 提取 → 重构 → 验证
核心概念
浅层模型(Anemic Model)是什么
浅层模型的特征:
- 实体只有 getter/setter,没有业务行为
- 业务规则散落在 Service/Controller/SQL 中
- 模型只是"数据的容器",不表达业务意图
典型症状:
text
class Order { // 浅层:只有数据
String status
List<OrderItem> items
// 没有 pay()、cancel()、addItem() 等业务方法
}
class OrderService { // 规则散落在这里
void pay(Order order) {
if (order.status == "CREATED" && order.items.size > 0) {
order.status = "PAID" // 直接改字段
}
}
}
深层模型(Rich Model)是什么
深层模型的特征:
- 实体/值对象包含业务行为
- 业务规则封装在模型内部
- 模型用领域术语表达,领域专家能理解
本书示例的"订单模型"就是深层模型的示例:
pay()、cancel()、addItem()等方法封装业务规则OrderStatus状态机显性化状态转换约束OrderPaymentSpecification显性化"可支付"规则
隐含概念(Implicit Concept)是什么
隐含概念是"业务讨论中存在,但代码中没有显性表达"的概念。例如:
- 业务说"订单可支付",代码里是
if (status == "CREATED" && ...) - 业务说"订单行数限制",代码里是
if (items.size() >= 50) - 业务说"订单状态转换",代码里是
order.status = "PAID"
重构的目标是:把这些隐含概念提取成显性的领域对象(规约、值对象、状态机等)。
课堂讲授:从浅层到深层的重构路径
步骤 1:识别隐含概念
通过以下信号识别:
- 业务讨论中的名词:例如"可支付条件""订单行数限制"
- 散落的 if/else:同样的判断逻辑在多处重复
- 魔法数字/字符串 :例如
50、"CREATED"、"PAID"
步骤 2:提取并显性化
把隐含概念提取成:
- 值对象 :例如
OrderStatus(状态机)、Money(金额+币种) - 规约 :例如
OrderPaymentSpecification(可支付规则) - 常量/枚举 :例如
MAX_ORDER_LINES = 50
步骤 3:重构模型行为
把散落的规则移回模型:
- 从
OrderService.pay()移到Order.pay() - 从
if/else移到规约/状态机方法
步骤 4:验证与迭代
通过测试验证重构后的模型:
- 业务规则是否仍然正确
- 代码是否更易读、更易维护
伪代码示例:从浅层到深层的重构
重构前(浅层)
text
class Order {
String status
List<OrderItem> items
}
class OrderService {
void pay(Order order) {
if (order.status.equals("CREATED")
&& order.items.size() > 0
&& order.totalAmount > 0) {
order.status = "PAID"
// 发布事件...
}
}
}
重构后(深层)
text
class Order {
OrderStatus status
List<OrderItem> items
pay():
require OrderPaymentSpecification().isSatisfiedBy(this)
status = status.transitionToPaid()
domainEvents.add(OrderPaidEvent(...))
}
class OrderPaymentSpecification {
isSatisfiedBy(order):
return order.status.canPay()
and order.totalAmount > 0
and order.items not empty
}
class OrderStatus {
canPay(): value == CREATED
transitionToPaid(): require value == CREATED; return OrderStatus(PAID)
}
重构策略:何时重构、如何重构
何时重构
- 发现重复的业务规则:同样的判断在多处出现
- 业务规则变化频繁:规则散落导致修改困难
- 领域专家看不懂代码:代码与技术细节耦合,业务意图不清晰
如何重构(小步快跑)
- 先提取值对象/规约:把魔法值/散落规则提取出来
- 再移回模型行为:把 Service 里的规则移到聚合/值对象
- 最后优化表达:用领域术语命名,让代码"说业务话"
常见误区
- 误区 1:一次性大重构:风险高、容易出错;应该小步快跑,每次重构后测试通过
- 误区 2:过度设计:为了"深层"而深层,引入不必要的抽象
- 误区 3:忽略业务价值:重构应该让业务规则更清晰、更易维护,而不是"看起来高级"
- 误区 4:重构后不更新测试:测试应该同步演进,验证重构后的模型
课堂练习
- 以"订单模型"为例,请列出 3 个"从浅层到深层"的重构点(例如:用状态机显性化状态转换、用规约显性化规则、提取常量/值对象等)。
- 假设你看到一个
OrderService里有这样的代码:
text
if (order.status == "PAID" && order.shippingAddress != null) {
order.status = "SHIPPED"
}
请设计一个重构方案,把这段逻辑移到深层模型(提示:考虑状态机与规约)。
- 给出一个你认为"隐含概念"的例子(来自你的项目或想象),并说明如何显性化。
自测题
- 浅层模型与深层模型的关键区别是什么?
- 如何识别"隐含概念"?
- 为什么说"重构应该小步快跑"?
延伸阅读
- 参考资料索引:
references.md