我是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 });
}
}
答案 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技术,更易于维护,易于测试,因为订单只是一个现在界面等。