Fra*_*kra 5 architecture domain-driven-design node.js sequelize.js rich-domain-model
我正在重新设计NodeJS应用程序,因为我想使用Rich Domain Model概念。目前,我正在使用Anemic域模型,并且扩展性不好,我到处都看到“ ifs”。
我已经阅读了许多博客文章和与DDD相关的博客,但是有些事情我根本无法理解...我们如何正确处理持久性。
首先,我想描述一下我定义的图层及其用途:
持续性模型
领域模型
数据访问对象(DAO)
服务层
客户层
现在,当我实现客户端层时,混乱就开始了。
假设我正在实现一个新的REST API:
POST: .../api/CreateOrderForUser/
{
items: [{
productId: 1,
quantity: 4
},{
productId: 3,
quantity: 2
}]
}
Run Code Online (Sandbox Code Playgroud)
在我的处理程序函数上,我将有类似以下内容:
function(oReq){
var oRequestBody = oReq.body;
var oCurrentUser = oReq.user; //This is already a Domain Object
var aOrderItems = oRequestBody.map(function(mOrderData){
return new OrderItem(mOrderData); //Constructor sets the properties internally
});
var oOrder = new Order({
items: aOrderItems
});
oCurrentUser.addOrder(oOrder);
// So far so good... But how do I persist whatever
// happened above? Should I call each DAO for each entity
// created? Like, first create the Order, then create the
// Items, then update the User?
}
Run Code Online (Sandbox Code Playgroud)
我发现使它起作用的一种方法是合并持久性模型和域模型,这意味着oCurrentUser.addOrder(...)它将执行所需的业务逻辑,并将调用OrderDAO最终将Order和Items持久化。不好的事情是,现在addOrder还必须处理事务,因为我不想添加没有项目的订单,也不想更新没有订单的用户。
那么,我在这里想念的是什么?
这是故事中缺失的部分。
在您的示例中,订单项可能没有单独的表(并且没有关系,没有外键......)。这里的项目似乎是值(描述一个实体,即:“45 美元”),而不是实体(我们跟踪的随时间变化的事物,即:银行账户)。因此,您不会直接保留 OrderItems,而是仅保留订单(及其中的项目)。
我希望找到代替您的评论的代码可能如下所示orderRepository.save(oOrder);。此外,我希望用户是订单中的弱引用(仅通过 id),而不是像代码所oCurrentUser.addOrder(oOrder);建议的那样包含在用户中的订单。
此外,您描述的层是有意义的,但在您的示例中,您将交付问题(请求、响应等概念......)与域概念(将项目添加到新订单)混合在一起,我建议您看看已建立的模式使这些问题保持解耦,例如六边形架构。这对于单元测试尤其重要,因为您的“客户端代码”可能是测试而不是处理程序函数。检索/创建 - 执行某些操作 - 保存代码通常是描述您的用例的应用程序服务中的函数。
Vaughn Vernon 的“实现领域驱动设计”是一本关于 DDD 的好书,它肯定会对这个主题有更多的启发。