返回

DDD 碎片记录 02:服务、实体、值对象——粒度分解,清晰架构

数据库

服务、实体和值对象:DDD 架构的基石

在构建健壮且可维护的软件系统时,分解复杂业务领域至关重要。领域驱动设计 (DDD) 提供了一套强大的概念,包括服务、实体和值对象,以实现这一目标。

服务:动作与行为的执行者

服务是独立于领域对象之外的组件,负责执行特定的操作或行为。它们扮演着中介者的角色,接受用户请求,根据业务规则执行相应操作,并返回结果。

服务主要负责以下职责:

  • 执行领域操作: 服务封装了无法直接通过实体或值对象执行的领域操作,例如下单、更新客户信息等。
  • 协调对象交互: 服务可以协调多个实体或值对象之间的交互,例如在完成订单时更新库存和客户余额。
  • 提供统一接口: 服务提供了一个统一的接口,使外部系统或用户能够访问领域功能,无需了解内部实现细节。

示例代码:

public class OrderService {

    public Order createOrder(Customer customer, List<Product> products) {
        // 执行业务规则,创建订单
        Order order = new Order(customer, products);
        // 持久化订单
        orderRepository.save(order);
        // 返回创建的订单
        return order;
    }
}

实体:业务概念的持久化表示

实体是对业务概念的持久化表示,具有唯一标识符,能够随着时间推移而独立存在。实体包含了业务概念的状态和行为,并通过方法公开其接口。

实体的主要特征如下:

  • 唯一标识符: 实体具有一个唯一的标识符,该标识符在整个系统中都是唯一的。
  • 状态和行为: 实体包含与业务概念相关的数据和行为,这些数据和行为被持久化存储在数据库或其他持久性存储中。
  • 不变性规则: 实体通常具有不变性规则,这些规则定义了实体状态的约束条件,例如客户的姓名不能为空。

示例代码:

public class Customer {

    private Long id;
    private String name;
    private String address;

    // getter 和 setter 方法
}

值对象:不可变的、性的数据

值对象是对不可变、性数据的封装。它们不具有标识符,并且其值一旦创建就无法更改。值对象通常用于表示业务概念中的附加信息或属性。

值对象的主要特点如下:

  • 不可变性: 值对象一旦创建就不能更改。
  • 性数据: 值对象包含与业务概念相关的不变性数据,例如客户的地址或订单的总金额。
  • 值相等性: 值对象通过比较其值来确定相等性,而不是通过比较其标识符。

示例代码:

public class Address {

    private String street;
    private String city;
    private String state;
    private String zipCode;

    // getter 和 setter 方法

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return street.equals(address.street) &&
                city.equals(address.city) &&
                state.equals(address.state) &&
                zipCode.equals(address.zipCode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(street, city, state, zipCode);
    }
}

粒度的艺术

DDD 的核心原则是将领域对象分解成粒度更细的组件。这种分解可以通过多种方式实现,但服务、实体和值对象通常是首选工具。

选择正确的粒度至关重要。粒度过大会导致笨重的对象和难以维护的代码,而粒度过小会导致过多的对象和不必要的复杂性。需要在灵活性、可维护性和性能之间取得适当的平衡。

清晰架构的基石

服务、实体和值对象构成了 DDD 架构的基石。通过合理运用这些概念,我们可以构建出清晰、灵活且易于维护的系统。

最佳实践

  • 使用服务来封装与领域对象无关的操作和行为。
  • 实体应该只包含业务概念的状态和行为,避免将其用作数据传输对象。
  • 值对象应该只包含描述性数据,避免将其用作实体或服务的替代品。
  • 粒度分解应该小心进行,以实现最佳的灵活性、可维护性和性能平衡。

结论

服务、实体和值对象是 DDD 中构建清晰、可维护的领域模型的关键概念。通过理解这些概念并正确应用它们,我们可以显着提高软件系统的质量和可扩展性。

常见问题解答

  1. 服务和方法有什么区别?
    服务是独立的组件,负责执行领域操作,而方法是实体或值对象的一部分,用于执行该对象的特定行为。

  2. 何时使用值对象而不是实体?
    当数据不可变、没有标识符,并且不需要单独持久化时,使用值对象。

  3. 如何确定正确的粒度?
    正确的粒度是一个平衡问题,需要在灵活性、可维护性和性能之间做出权衡。

  4. DDD 是否适用于所有应用程序?
    DDD 最适用于复杂、领域驱动的应用程序,需要对业务概念进行建模和管理。

  5. DDD 是否有替代方案?
    DDD 是构建领域驱动应用程序的流行方法,但也有其他方法,例如事件溯源和命令查询职责分离 (CQRS)。