第5章:对象设计(Object Design)
一、导读
1.1 本章学习目标
第5章讲解如何用测试驱动对象设计。通过测试来发现设计问题,推动更好的抽象。
1.2 为什么第五章如此重要
TDD 的核心价值不是测试,而是设计。测试是发现设计问题的工具。
1.3 核心问题引导
如何通过测试发现设计问题?
职责驱动设计是什么?
依赖注入如何改善设计?
值对象有什么特殊之处?
二、核心概念详解
5.1 职责驱动设计
设计原则:
- 每个对象负责一件事
- 对象之间通过消息通信
- 高内聚、低耦合
测试揭示设计问题:
- 测试难以编写 → 职责不清
- 需要太多 Mock → 依赖太多
- 测试脆弱 → 接口不稳定5.2 依赖注入
java
// 反模式:硬编码依赖
public class OrderService {
private PaymentGateway gateway = new StripeGateway();
}
// 正确做法:依赖注入
public class OrderService {
private final PaymentGateway gateway;
public OrderService(PaymentGateway gateway) {
this.gateway = gateway;
}
}
// 测试时可以注入 Mock
OrderService service = new OrderService(mockGateway);5.3 值对象
java
// 值对象:通过值相等,不可变
public final class Money {
private final BigDecimal amount;
private final Currency currency;
public Money(BigDecimal amount, Currency currency) {
this.amount = amount;
this.currency = currency;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Money)) return false;
Money m = (Money) o;
return amount.equals(m.amount) && currency.equals(m.currency);
}
@Override
public int hashCode() {
return Objects.hash(amount, currency);
}
}三、实战案例
5.1 测试驱动设计
java
// 测试难以编写 → 设计有问题
@Test
public void shouldCreateOrder() {
// 需要创建数据库、缓存、消息队列...
// 说明 OrderService 职责太多
}
// 重构:拆分职责
@Test
public void shouldCreateOrder() {
OrderService service = new OrderService(
mockRepo, mockCache, mockEventBus);
service.create(order);
verify(mockRepo).save(order);
verify(mockEventBus).publish(new OrderCreated(order));
}
// 测试容易编写 → 设计更清晰四、本章小结
测试是设计的工具。通过测试可以发现设计问题,推动更好的抽象。职责驱动设计、依赖注入和值对象是 TDD 中常用的设计技术。
五、思考与练习
如何通过测试发现设计问题?
依赖注入有什么优势?
值对象和实体有什么区别?
如何平衡测试的简洁性和覆盖度?
如何用测试驱动接口设计?