2

在包含大量 CRUD 功能的应用程序中实现 DDD 时,再加上某种 web-API,您最终会遇到这样一种情况:使用平台提供的工具可以使相对简单的事情变得更加困难。例如:

假设我们有一个 User 对象,并且您正在努力不创建贫血的域模型,因此您可以建模更具表现力的操作:

class User {
    public void terminateAccount(TeminationReason reason);
    public void reactivateAccount();
}

上面的类很好,因为它让我们可以将帐户标记为已终止并立即设置原因。显然是对 setEnabled(false) 和 setTerminationReason(..) 的改进。

问题是,假设我们有类似 JAX-RS Web 服务的东西,它可以 GET/PUT 覆盖该用户。该框架(JAX-RS、JAXB)将为我们轻松地序列化和反序列化我们的 DTO 对象。现在,我们以前可以做的:

entity.setEnabled(dto.isEnabled);
entity.setTerminationReason(dto.getTerminationReason);

我们必须改为:

if (entity.isEnabled() && !dto.isEnabled()) {
    entity.terminateAccount(dto.getTerminationReason);
} else if (!entity.isEnabled && dto.isEnabled) {
    entity.reactivateAccount();
}

这里最大的脱节是领域对象的面向业务的接口,以及 RESTful API 上的 CRUD 样式访问模式。由于 DDD 和 REST 本身都是最佳实践,这里的每个人都学到了什么教训来减少上面的代码痛苦/重复/等等?

PS - 我们使用 DTO 是因为在幕后使用 ORM 框架时,实际上将实体序列化为 XML/JSON 是有问题的,因为我们无法限制延迟加载。您通常还希望通过 RESTful API(参考 URL 等)公开不属于域模型的不同属性。我也愿意接受这里的建议。

4

1 回答 1

4

我认为这里的问题是您正在尝试使用单个 DTO 来表示User所有 API 中的实体。相反,如果每个操作都有一个单独的 DTO,只包含所需的数据,那么您的代码会简单得多。

例如,TerminateAccountAPI 将有一个仅包含终止原因的 DTO,而您的代码将是:

user.terminateAccount(dto.terminationReason);
于 2012-07-23T03:43:23.887 回答