谁负责DDD(域驱动设计)的域层中API请求的处理过程

时间:2019-01-19 10:31:08

标签: domain-driven-design

我是DDD的初学者。

我不知道谁负责API请求过程。
我不知道谁负责间接依赖基础结构层的功能。
例如带有Web API请求的功能。

例如,我正在创建在线购物系统,该系统支持取消订单。

我认为我在域层有2个候选类来实现订单取消功能。   答:域名服务   B:域对象

但是我无法判断哪个更好。

我担心设计“ A”的程序性太强,看起来太贫乏了。
我还担心设计“ B”会使领域对象过于专业和依赖。 (因为我认为对象应该尽可能简单)

设计候选人A

// Simple but anemic
class Order {
    id: number;
    date: Date;
    state: OrderState;

    constructor(
        ...
    ) {
        ...
    }
}

// Procedural
class OrderService {
    private readonly orderRepository: OrderRepository;

    constructor(
        orderRepository: OrderRepository
    ) {
        ...
    }

    cancel(orderId: number): void {
        orderRepository.update(orderId, { state: OrderSate.Cancelled });
    }
}

设计候选B

// knowledgeable and dependent
class Order {
    id: number;
    date: Date;
    state: OrderState;

    private readonly orderRepository: OrderRepository;

    constructor(
        orderRepository: OrderRepository,
        ...
    ) {
        ...
    }

    cancel(): void {
        orderRepository.update(this.id, { state: OrderSate.Cancelled });
    }
}

The model I thought

2 个答案:

答案 0 :(得分:1)

  

我是DDD的初学者。我不知道谁负责API请求过程。

业务逻辑属于领域模型,业务流程属于应用程序。

因此,您的应用程序中的逻辑通常看起来像...

Order order = orderRepository.get(orderId);
order.cancel();

订购模型负责负责在调用Order::cancel时如何操纵其自身的内存数据结构。 OrderRepository负责持久性。该应用程序驱动其他两个元素的调用。

混乱的部分原因是“服务”概念超载。在DDD中,“域服务”是指作为域模型一部分的模式(就像值对象和实体是域模型模式一样)。

更新20190120

  

但是谁来更新服务器中的数据库?您的代码似乎如果order.cancel()仅更新自己的内存,则服务器中的数据库尚未更新。这是我的想法。

这是一个非常重要的问题,不是吗? :)

当Eric Evans在他的书中首次描述存储库模式时,他特意选择了具有集合语义的存储库模式,并建议事务管理应成为 application 的关注点。

使用伪代码:

beginTransaction();
Order order = orderRepository.get(orderId);
order.cancel();
commitTransaction();

概念是基础 mapper 可以查看存储库并发现哪些实体是“脏”的,从而生成对持久存储的适当调用。

最近,您更有可能看到具有存储而不是集合语义的存储库

beginTransaction();
Order order = orderRepository.get(orderId);
order.cancel();
orderRepository.save(order);
commitTransaction();

基本机制相同,但是我们消除了共享更改方式的一些魔力。

答案 1 :(得分:0)

这些选项还有其他选择。一种是消除存储库中的东西,并让模型定义行为:

public interface Order {
    void cancel();
}

然后在特定技术的帮助下实现该行为:

public final class SqlOrder implements Order {
    ...
    @Override
    public void cancel() {
        connection.execute("update order...");
    }
}

根据您的用例,这可能会带来以下好处:不贫乏,摆脱潜在的不必要的间接访问(存储库),使用域语言而不是CRUD技术,更易于维护,易于测试,因为订单只是一个现在界面等。