在处理DDD几个月后,我仍然对域服务、工厂和聚合根的一般用途感到困惑,例如它们的职责重叠的地方。
示例:我需要1)在一个saga (流程管理器)中创建一个复杂的域实体,然后是一个需要在其他地方处理的特定域事件,而3)该实体显然是一个聚合根,它标记了其他实体的有界上下文。
当我将聚合根和工厂的概念引入到我的域中时,服务似乎不再需要了。但是,如果我不是,服务也可以用他所拥有的知识和依赖来处理所需的一切。
基于普适语言的汽车修理厂代码示例
public class Car : AggregateRoot {
private readonly IWheelRepository _wheels;
private readonly IMessageBus _messageBus;
public void AddWheel(Wheel wheel) {
_wheels.Add(wheel);
_messageBus.Raise(new WheelAddedEvent());
}
}
public static class CarFactory {
public static Car CreateCar(string model, int amountofWheels);
}..or...
public class Car {
public ICollection<Wheel> Wheels { get; set; }
}
public interface ICarService {
Car CreateCar(args);
void DeleteCar(args);
Car AddWheel(int carId, Wheel wheel);
}发布于 2016-01-12 01:23:20
在处理DDD几个月后,我仍然对域服务、工厂和聚合根的一般用途感到困惑,例如它们的职责重叠的地方。
聚合根负责确保状态与业务不变量一致。在CQRS术语中,您可以通过向聚合根发出命令来更改模型。
域服务是聚合的查询支持机制。例如,域服务可能支持计算。命令处理程序将域服务传递给聚合,聚合(处理命令)需要计算结果,因此它将将其状态中作为计算输入的部分传递给域服务。域服务进行计算并返回结果,然后聚合将决定如何处理结果。
“工厂”可能意味着几件事。如果您使用工厂来创建一个位于聚合边界内的实体,那么它只是一个实现细节--如果对象的构造很复杂,您可以使用它。
在某些情况下,使用“储存”一词。这通常意味着它是负责创建聚合根的持久化层(而不是域模型的一部分)的一部分。粗略地说,命令处理程序(这是应用程序的一部分)验证一个命令,然后使用Repository加载命令寻址到的聚合根。然后,命令处理程序将在聚合根上调用指定的方法,从命令对象传入参数,也可能传入域服务作为参数。
在您的示例中,要问的关键问题是,决定是否运行命令的责任在哪里?应用程序负责确保命令格式良好(所有命令数据都存在,数据被转换为域识别的值,而不抛出验证错误等等)。但是谁能决定“不,你现在不能加一个轮子--商业规则不允许它!”
在DDD世界中,这无疑是总根的责任。因此,确定这一点的任何逻辑都应该位于聚合根目录中,而ICarService就会消失。
(在替代实现中,聚合公开其状态,而cars服务检查业务规则并操作对象的状态,被视为反模式--一个“贫血”聚合的例子。集合中的“设置者”是一种代码气味。聚合中的"Getters“通常是一种代码气味--尤其是在CQRS中,在读取模型中,支持查询的责任应该是”其他地方“)。
发布于 2014-05-05 08:15:00
DDD在一定程度上是对贫血域模型的反应,在该模型中,实体只具有状态,而不具有行为。
的确,从某种意义上说,你可以把汽车的所有行为都放在一个单独的服务中,但你为什么要这样做呢?要做到这一点,您需要在汽车中公开各种状态,通常您希望保持私有状态(比如车轮)。
如果你像那样暴露轮子,任何代码都可以对这个集合做各种古怪的事情,除了任何正常的业务流程之外。请记住,聚合的意义在于在业务流程事务之间具有事务一致性。像那样暴露车轮完全破坏了安全。
例如:假设你的公司只想支持四个轮子的汽车。如果封装了对车轮的访问,则可以强制执行。如果你不这样做,这是完全有可能增加100个车轮的汽车,因为车轮将暴露。
服务通常用作协调器。命令处理程序(假设类似于CQRS)将命令对象转换为更强类型的参数,从而减少了原始的痴迷。然后,它可以使用更多的“域-ish”参数调用服务。服务从存储库中检索实体并调用它们的行为。根据您的体系结构,它可以收集任何更改(事件),并将它们传递给总线或其他任何东西。
在更高级的场景中,您将使用一个工作单元来跟踪所有实体,并可以一次性收集所有实体的更改。
至于工厂(作为旁白),没有什么可以阻止您添加静态工厂方法(您的聚合类),而不是创建一个单独的工厂。
https://softwareengineering.stackexchange.com/questions/237943
复制相似问题