写点什么

战术领域驱动设计:将战略融入代码实践

作者:qife122
  • 2025-11-12
    福建
  • 本文字数:2491 字

    阅读完需:约 8 分钟

战术领域驱动设计:将战略融入代码

在之前的文章中,我讨论了领域驱动设计中最常被忽视的方面:战略层面。在软件开发中,团队往往急于编写代码,认为实现会澄清领域。历史表明相反的情况——在没有理解根本原因或方向的情况下构建系统,通常会导致系统在技术上正确但在概念上错误。


既然我们已经探讨了“为什么”和“什么”,现在是时候转向“如何”了。战术 DDD 代表了下一步——将充分理解的领域转化为表达性强、可维护代码的过程。


战术 DDD 专注于实现领域模型。它提供了丰富的设计模式词汇——实体、值对象、聚合、仓储和领域服务——每个模式在表达业务逻辑方面都有精确的用途。


战术 DDD 的基本能力是创建不仅准确而且能够适应变化的模型。这一层将战略模型的概念清晰性与实现的实践需求连接起来。战术设计确保业务规则被捕获在代码中,而不是分散在服务、控制器或数据库脚本中。


战术部分由七个基本模式组成,将概念转化为代码:


  • 实体——具有身份的对象,持久存在并演化

  • 值对象——仅由其属性定义的不可变对象

  • 聚合——确保一致边界的相关实体组

  • 仓储——抽象聚合持久化的接口

  • 工厂——负责创建复杂的领域对象

  • 领域服务——保存不适合实体或值对象的领域逻辑

  • 领域事件——捕获并传达域中的重要发生

实体

实体代表具有唯一身份或 ID 的领域对象,即使其属性可能改变,身份也会随时间持续存在。它们建模连续性——即使数据演化,某些东西保持不变。


public class Order {    private final UUID orderId;    private List<OrderItem> items = new ArrayList<>();    private OrderStatus status = OrderStatus.NEW;        public void addItem(OrderItem item) {        items.add(item);    }}
复制代码

值对象

值对象描述完全由其值而非身份定义的领域元素。它们是不可变的、可替换的,并通过内容确保相等性。


public record Money(BigDecimal amount, String currency) {    public Money add(Money other) {        if (!currency.equals(other.currency())){            throw new IllegalArgumentException("Currencies must match");        }        return new Money(amount.add(other.amount()), currency);    }}
复制代码

聚合

聚合在单个一致性边界下组织相关实体和值对象,确保业务规则保持有效。聚合根充当其内部状态的守护者。


public class Order {    private final UUID orderId;    private final List<OrderItem> items = new ArrayList<>();        public void addItem(Product product, int quantity) {        items.add(new OrderItem(product, quantity));    }        public BigDecimal total() {        return items.stream()                   .map(OrderItem::subtotal)                   .reduce(BigDecimal.ZERO, BigDecimal::add);    }}
复制代码

仓储

仓储抽象了聚合的存储和检索方式,使领域保持独立于数据库关注点。它们充当处理持久化的内存集合。


public interface OrderRepository {    Optional<Order> findById(UUID id);    void save(Order order);    void delete(Order order);}
复制代码

工厂

工厂负责创建复杂的领域对象,同时确保所有不变量得到满足。它们集中创建逻辑,使实体免于构建复杂性。


public class OrderFactory {    public Order create(Customer customer, List<Product> products) {        Order order = new Order(UUID.randomUUID(), customer);        products.forEach(p -> order.addItem(p, 1));        return order;    }}
复制代码

领域服务

领域服务保存不适合实体或值对象的领域逻辑。它们表达涉及多个聚合或横切业务规则的行为。


public class PaymentService {    private final PaymentGateway gateway;        public PaymentService(PaymentGateway gateway) {        this.gateway = gateway;    }        public PaymentReceipt processPayment(Order order, Money amount) {        return gateway.charge(order.getOrderId(), amount);    }}
复制代码

领域事件

领域事件捕获业务域中的重要发生。它们代表发生的事情——不是外部触发器,而是域本身想要共享的事实。


public record OrderPlacedEvent(UUID orderId, Instant occurredAt) {    public static OrderPlacedEvent from(Order order) {        return new OrderPlacedEvent(order.getOrderId(), Instant.now());    }}
复制代码

应用服务——编排用例

虽然应用服务不是原始七个战术 DDD 模式的一部分,但它们在现代架构中的作用值得提及。它们充当用例编排器,协调领域操作而不包含业务逻辑本身。


public class OrderApplicationService {    private final OrderRepository repository;    private final PaymentService paymentService;    private final OrderFactory factory;        public OrderApplicationService(OrderRepository repository,                                   PaymentService paymentService,                                   OrderFactory factory) {        this.repository = repository;        this.paymentService = paymentService;        this.factory = factory;    }        @Transactional    public void placeOrder(Customer customer, List<Product> products) {        Order order = factory.create(customer, products);        repository.save(order);        paymentService.processPayment(order, order.total());    }}
复制代码


在实践中,应用服务作为用例的入口点,管理事务、调用领域逻辑并根据需要触发外部集成。

结论

战术领域驱动设计将战略变为现实。虽然战略方面定义边界和共享理解,但战术模式——实体、值对象、聚合、仓储、工厂、领域服务和领域事件——将该愿景转化为表达性强、可维护的代码。即使是应用服务,虽然不是原始七个模式的一部分,也在编排用例和维护模型纯度方面发挥着重要作用。更多精彩内容 请关注我的个人公众号 公众号(办公 AI 智能小助手)对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)


公众号二维码


办公AI智能小助手


公众号二维码


网络安全技术点滴分享


用户头像

qife122

关注

还未添加个人签名 2021-05-19 加入

还未添加个人简介

评论

发布
暂无评论
战术领域驱动设计:将战略融入代码实践_领域驱动设计_qife122_InfoQ写作社区