architecture - 从 N 层转换为 DDD
问题描述
我正在努力理解如何通过让我的域实体有自己的行为来将我的网站重构为更简洁的代码。
我希望我已经设法在这张图中描述了我的问题:
A是我当前设计的 Web 应用程序项目,而B是我的目标设计。
我正在尝试将我当前 BL 中的所有逻辑插入到我的实体中,以便如下代码行:
var customer = new CustomerLogic().GetCustomer(id);
将变为:
var customer = new Customer(id);
或者,
var customer = Customer.Get(id);
当我看到多态情况时,这一点就更加明显了。
问题是,虽然在我当前的设计中(A)实体只是被使用,所以所有项目都有对它的引用,而未来的设计(B)实体将必须对较低层有引用。
但是由于我还希望我的 DAL 将我的实体交付回调用客户端,所以我得到了一个循环引用。
我目前的设计使我的代码比面向对象更程序化,我想改变它。
那么,如何在维护 DDD 的同时解决此循环引用?
解决方案
您可以通过反转来自实体的依赖关系来解决循环依赖关系(在 DDD 中是聚合,其中每个聚合包含一个聚合根和零个或多个嵌套实体)。换句话说,领域层不应该对其他层有任何依赖,比如持久性、应用程序或表示。
一个完整的用例是这样的:
customerId = request.get('customer_id')
customer = repository.load(customerId)
customer.doSomethingImportant() //business logic that doesn't need anything from other layers
repository.save(customer)
如果不知何故,您的聚合需要一些来自外部的信息来完成其工作,那么您将该信息作为参数传递,如下所示customer.doSomethingImportant(some, info, fromOutside)
:
您应该在此处注意的重要方面是 Aggregate 的方法不会改变除了它自己的 state 之外的任何其他内容。例如,它不发送电子邮件,不写入文件,甚至不写入数据库。然后,该突变状态由存储库获取并保存在数据库中。通过这种方式,您可以反转对 DAL/数据库的依赖关系。
在事件溯源中,这种变异状态采用领域事件的形式。在平面/经典架构中,存储库(通常是 ORM)计算差异并对数据库执行更改。
推荐阅读
- c++ - 在函数中动态分配数组
- opencv - 为语义分割创建索引像素
- firefox - 如何从 Android 上的 Firefox 访问路由器的 IP 地址?
- typescript - 键入'字符串 | number' 不能分配给 switch 语句中的类型 'never'
- python-3.x - 尝试构建调度应用程序,我应该学习什么?
- heroku - heroku 重定向到文件,同时隐藏 url
- python - Discord bot 删除用户的所有消息
- google-sheets - 当函数在我的数据源中以不同方式显示时,如何在函数中引用 URL?
- c# - OLEDBConnection:将字节 [] 插入 blob 不会保存更改
- scala - 如何在 Streamsets 中使用 Scala 或 Pyspark 使用 Apache Spark 进行机器学习?