Skip to content

三个服务和领域对象的职责

要理解DDD中领域对象领域服务应用服务基础设施服务的边界,核心是抓住「业务规则的归属」和「技术细节的隔离」。以下从定义-职责-边界-例子四维度展开,并结合「用户下单」流程具体说明。

一、核心概念与职责边界

先通过一句话总结对比表格明确每个组件的定位:

组件所在层核心职责关键特征禁止做的事
领域对象领域层封装领域状态(数据)和自身相关的业务行为(方法),是业务规则的“原子载体”。有状态、富行为(非贫血模型)依赖技术细节(如数据库、API)
领域服务领域层处理跨领域对象的业务规则无法归属单个对象的逻辑,是业务规则的“组合器”。无状态、纯业务逻辑处理技术细节(如保存数据)
应用服务应用层作为用例入口,协调领域对象/服务完成流程,不包含业务规则。无状态、流程协调包含任何业务规则
基础设施服务基础设施层提供技术实现能力(数据库、第三方API、消息队列等),是领域层的“工具库”。实现抽象接口(依赖倒置)包含任何业务规则

1. 领域对象(Domain Object):业务规则的“原子载体”

定义:领域的核心构件,包括实体(Entity)(有唯一标识,如OrderProduct)和值对象(Value Object)(无唯一标识,如UserAddressMoney)。
职责

  • 封装自身状态(如订单的商品列表、用户地址);
  • 实现自身相关的业务行为(如订单计算总价、商品扣减库存);
  • 保证自身状态的一致性(如扣库存时检查是否足够)。

例子

  • Order实体:包含orderIdlines(商品行)、totalPrice(总价),有calculateTotalPrice()方法(自己计算总价);
  • Product实体:包含productIdstock(库存),有reduceStock(int quantity)方法(自己扣减库存,且检查库存是否足够);
  • UserAddress值对象:包含provincecitystreet,有isValid()方法(自己验证地址格式是否合法)。

2. 领域服务(Domain Service):跨对象业务规则的“组合器”

定义:当业务规则无法归属单个领域对象(需跨多个对象协作)时,用领域服务封装。
职责

  • 处理跨领域对象的业务规则(如验证订单库存需查所有商品的库存);
  • 处理不属于单个对象的逻辑(如复杂定价规则:满减+优惠券);
  • 无状态(不保存数据,仅做逻辑计算)。

关键判断:如果一个逻辑需要询问多个领域对象(而非让单个对象“自己做”),则用领域服务。

例子

  • OrderValidationService:验证订单的库存(需遍历Order的商品行,查询对应Product的库存)、验证地址(需结合User的地区和UserAddress的有效性);
  • PricingService:计算订单最终价格(需结合Order的总价、Coupon的折扣、User的会员等级)。

3. 应用服务(Application Service):用例流程的“协调者”

定义:应用层的入口,对应用户/系统的用例(如“下单”“退款”),负责协调领域层和基础设施层完成流程。
职责

  • 接收外部请求(如REST API的PlaceOrderRequest),转换为领域对象(如OrderLineUserAddress);
  • 协调流程:调用领域服务验证规则→调用领域对象执行行为→调用基础设施服务保存数据;
  • 返回结果(如订单ID),不包含任何业务规则。

关键特征:应用服务是“无业务规则的流程管家”,它只关心“先做什么、后做什么”,不关心“怎么做”(怎么做由领域层负责)。

4. 基础设施服务(Infrastructure Service):技术细节的“实现者”

定义:负责提供技术能力,实现领域层定义的抽象接口(依赖倒置原则),隔离业务逻辑与技术细节。
职责

  • 实现持久化(如OrderRepository保存订单到数据库);
  • 调用第三方服务(如NotificationService发送短信、PaymentGateway调用微信支付);
  • 处理中间件(如消息队列发送异步消息)。

关键原则:领域层定义抽象接口(如OrderRepository),基础设施层实现接口(如JpaOrderRepository),确保领域层不依赖具体技术。

二、“用户下单”流程:四者的分工实战

以下用代码片段+流程步骤说明“用户下单”中各组件的协作(伪代码,聚焦核心逻辑)。

1. 前提:定义领域层抽象接口

领域层定义需要的抽象(依赖倒置):

java
// 领域层:订单仓库接口(抽象)
public interface OrderRepository {
    void save(Order order);
}

// 领域层:商品仓库接口(抽象)
public interface ProductRepository {
    Optional<Product> findById(ProductId id);
    void save(Product product);
}

// 领域层:通知服务接口(抽象)
public interface NotificationService {
    void sendOrderPlacedNotification(User user, Order order);
}

2. 领域对象实现(核心业务规则)

java
// 领域对象:订单实体(Entity)
public class Order {
    private OrderId id;
    private UserId userId;
    private List<OrderLine> lines; // 商品行(值对象)
    private UserAddress address;   // 地址(值对象)
    private Money totalPrice;      // 总价(值对象)

    // 工厂方法:创建订单(保证状态一致性)
    public static Order create(UserId userId, List<OrderLine> lines, UserAddress address) {
        Order order = new Order();
        order.id = OrderId.generate();
        order.userId = userId;
        order.lines = lines;
        order.address = address;
        order.calculateTotalPrice(); // 自己计算总价(领域行为)
        return order;
    }

    // 领域行为:计算总价(自身业务规则)
    private void calculateTotalPrice() {
        this.totalPrice = lines.stream()
                .map(line -> line.getPrice().multiply(line.getQuantity()))
                .reduce(Money.ZERO, Money::add);
    }

    // 省略getter...
}

// 领域对象:商品实体(Entity)
public class Product {
    private ProductId id;
    private String name;
    private Money price;
    private int stock;

    // 领域行为:扣减库存(自身业务规则,保证状态一致)
    public void reduceStock(int quantity) {
        if (stock < quantity) {
            throw new InsufficientStockException("商品库存不足:" + name);
        }
        this.stock -= quantity;
    }

    // 省略getter...
}

// 领域对象:地址值对象(Value Object)
public class UserAddress {
    private String province;
    private String city;
    private String street;

    // 工厂方法:创建地址(验证格式)
    public static UserAddress create(String province, String city, String street) {
        validateAddress(province, city, street);
        return new UserAddress(province, city, street);
    }

    // 领域行为:验证地址有效性(自身业务规则)
    private static void validateAddress(String province, String city, String street) {
        if (StringUtils.isBlank(province) || StringUtils.isBlank(city) || StringUtils.isBlank(street)) {
            throw new InvalidAddressException("地址不能为空");
        }
        // 可扩展更多规则(如省份是否存在)
    }

    // 省略getter...
}

3. 领域服务实现(跨对象业务规则)

java
// 领域服务:订单验证服务(跨Order和Product)
@Service
public class OrderValidationService {
    private final ProductRepository productRepository;

    // 注入领域层抽象接口(依赖倒置)
    public OrderValidationService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    // 业务规则:验证订单库存是否充足(跨Order和Product)
    public void validateStock(Order order) {
        for (OrderLine line : order.getLines()) {
            Product product = productRepository.findById(line.getProductId())
                    .orElseThrow(() -> new ProductNotFoundException("商品不存在:" + line.getProductId()));
            if (product.getStock() < line.getQuantity()) {
                throw new InsufficientStockException("商品库存不足:" + product.getName());
            }
        }
    }

    // 业务规则:验证地址是否属于用户所在地区(跨User和UserAddress)
    public void validateAddress(User user, UserAddress address) {
        if (!user.getRegion().equals(address.getProvince())) {
            throw new InvalidAddressException("地址不在用户所在地区:" + user.getRegion());
        }
    }
}

4. 应用服务实现(流程协调)

java
// 应用服务:订单应用服务(对应“下单”用例)
@Service
public class OrderApplicationService {
    private final OrderRepository orderRepository;
    private final ProductRepository productRepository;
    private final UserRepository userRepository;
    private final OrderValidationService orderValidationService;
    private final NotificationService notificationService;

    // 注入所有依赖(领域服务+基础设施服务的抽象接口)
    public OrderApplicationService(OrderRepository orderRepository,
                                   ProductRepository productRepository,
                                   UserRepository userRepository,
                                   OrderValidationService orderValidationService,
                                   NotificationService notificationService) {
        this.orderRepository = orderRepository;
        this.productRepository = productRepository;
        this.userRepository = userRepository;
        this.orderValidationService = orderValidationService;
        this.notificationService = notificationService;
    }

    // 下单用例入口:接收命令对象(封装请求参数)
    public OrderId placeOrder(PlaceOrderCommand command) {
        // 1. 解析参数,获取领域对象
        User user = userRepository.findById(command.getUserId())
                .orElseThrow(() -> new UserNotFoundException("用户不存在:" + command.getUserId()));
        List<OrderLine> lines = buildOrderLines(command.getProductQuantities());
        UserAddress address = UserAddress.create(command.getProvince(), command.getCity(), command.getStreet());

        // 2. 调用领域服务验证业务规则
        orderValidationService.validateAddress(user, address); // 验证地址归属
        Order order = Order.create(user.getId(), lines, address); // 创建订单(自动算总价)
        orderValidationService.validateStock(order); // 验证库存

        // 3. 执行领域行为(扣减库存)
        deductStock(order);

        // 4. 调用基础设施服务:保存订单
        orderRepository.save(order);

        // 5. 调用基础设施服务:发送通知
        notificationService.sendOrderPlacedNotification(user, order);

        // 6. 返回结果(订单ID)
        return order.getId();
    }

    // 辅助方法:构建商品行(转换参数为领域对象)
    private List<OrderLine> buildOrderLines(List<ProductQuantityCommand> productQuantities) {
        return productQuantities.stream()
                .map(cmd -> {
                    Product product = productRepository.findById(cmd.getProductId())
                            .orElseThrow(() -> new ProductNotFoundException("商品不存在:" + cmd.getProductId()));
                    return OrderLine.create(product.getId(), product.getPrice(), cmd.getQuantity());
                })
                .collect(Collectors.toList());
    }

    // 辅助方法:扣减库存(调用Product的领域行为)
    private void deductStock(Order order) {
        for (OrderLine line : order.getLines()) {
            Product product = productRepository.findById(line.getProductId())
                    .orElseThrow(() -> new ProductNotFoundException("商品不存在:" + line.getProductId()));
            product.reduceStock(line.getQuantity()); // 调用商品自身的扣库存行为
            productRepository.save(product); // 保存更新后的商品(基础设施服务)
        }
    }
}

5. 基础设施服务实现(技术细节)

java
// 基础设施服务:订单仓库的JPA实现(实现领域层抽象接口)
@Repository
public class JpaOrderRepository implements OrderRepository {
    private final OrderJpaEntityRepository jpaRepository; // Spring Data JPA接口

    @Autowired
    public JpaOrderRepository(OrderJpaEntityRepository jpaRepository) {
        this.jpaRepository = jpaRepository;
    }

    @Override
    public void save(Order order) {
        // 转换领域对象为JPA实体(ORM映射)
        OrderJpaEntity jpaEntity = OrderJpaEntity.fromDomain(order);
        jpaRepository.save(jpaEntity);
    }
}

// 基础设施服务:通知服务的实现(调用第三方推送API)
@Service
public class PushNotificationService implements NotificationService {
    private final PushApiClient pushApiClient; // 第三方推送SDK

    @Autowired
    public PushNotificationService(PushApiClient pushApiClient) {
        this.pushApiClient = pushApiClient;
    }

    @Override
    public void sendOrderPlacedNotification(User user, Order order) {
        String message = String.format("您的订单%s已创建,总价%s元", order.getId(), order.getTotalPrice());
        pushApiClient.send(user.getPhone(), message); // 调用第三方API(技术细节)
    }
}

三、关键总结:避免常见误区

  1. 禁止领域对象依赖技术:领域对象不能调用数据库、API等,否则会污染业务逻辑(如Order不能有save()方法)。
  2. 禁止应用服务包含业务规则:应用服务只做流程协调,不能计算总价、验证库存(如placeOrder方法不能写if (product.stock < quantity))。
  3. 禁止领域服务处理技术细节:领域服务不能保存数据、调用API(如OrderValidationService不能调用productRepository.save())。
  4. 必须依赖倒置:领域层定义抽象接口,基础设施层实现,确保领域层独立于技术(如OrderRepository是接口,JpaOrderRepository是实现)。

通过以上例子,你可以清晰看到:所有业务规则都在领域层(领域对象/服务),应用层负责流程,基础设施层负责技术实现。这种分层方式让业务逻辑更纯粹、更易维护,也更能应对需求变化(比如换数据库只需要改基础设施层,不影响领域层)。