【问题标题】:Should I restrict the constuction of a domain object to an external service?我应该将域对象的构造限制为外部服务吗?
【发布时间】:2023-01-12 02:53:22
【问题描述】:
假设我有值对象 LicensePlate。它是汽车的一部分,汽车是我域中的一个实体。但是,构建板块的逻辑不属于我的域,我只是从域服务RegistrationAgency.obtainPlate(Car car) 获取它,在基础架构层中实现为DMV.obtainPlate(Car car),它调用外部 API。
现在,我觉得我应该将 LicensePlate 的构建限制在服务中,这样我就可以确定 LicensePlate 的任何实例都是有效的(即由注册机构制作)。这是一个合理的担忧吗?
无论如何,我能想到的解决方案是将 LicensePlate 的构造函数设为私有并向类添加一个静态工厂方法,比方说 LicensePlate.build(car, licenseNumberFactory),其中 LicenseNumberFactory 负责调用外部 API。那有多乱? DDD 呢?我尊重它吗?我应该只公开 LicensePlate 并避免所有这些吗?
【问题讨论】:
标签:
oop
domain-driven-design
clean-architecture
hexagonal-architecture
【解决方案1】:
我应该只公开 LicensePlate 并避免所有这些吗?
是的
值对象LicensePlate 应该能够执行它自己的不变量,例如不能为空/必须包含数字和字母/其他任何内容。
public class LicensePlate
{
public string RegNumber { get; init }
public LicensePlate(string regNumber)
{
if (string.IsNullOrWhitespace(regNumber))
throw ArgumentOutOfRangeException(nameof(regNumber));
// perform other invariant checks;
RegNumber = regNumber;
}
}
现在你有一个牌照可以强制执行它自己的不变量(至少在它的知识范围内)。您的汽车实体将类似于:
public class Car
{
public string Model { get; private set; }
public string Color { get; private set; }
public LicensePlate LicensePlate { get; private set; }
public Car(string model, string color, LicensePlate licensePlate)
{
Model = model;
Color = color;
LicensePlate = licensePlate;
}
}
所以我可以确定 LicensePlate 的任何实例都是有效的(即
注册机构制作)
如果 registration agency 意味着车牌必须由受信任的服务创建,那么这取决于基础设施来执行。
您可能认为任何呼叫者都可以创建一个牌照来放置在您的汽车实体上。这是真的。但是,如果该调用者无权访问您的基础设施(数据库),那么创建该实体不会造成任何风险,因为可能提供了欺骗牌照的调用者(基础设施)无法将其保留在您的基础设施(数据库)中。
如果可以访问您的数据库的同一基础架构代码库用于调用车牌生成 API,那么一切都很好。
如果一个完全不同的基础设施希望使用 Car 实体,但使用由不同服务(或测试时的模拟服务)创建的车牌,那么这取决于基础设施/应用程序层。事实上,这是 DDD 分层的一个特性。不能期望 Car 实体强制执行不受其控制的不变量(例如,值对象是否是从特定外部服务获取的)。
无论如何,我能想到的解决方案是制作 LicensePlate 的
私有构造函数并向类添加静态工厂方法,
假设 LicensePlate.build(car, licenseNumberFactory)
你可以这样做,但你仍然不知道 licenseNumberFactory 本身是否被基础设施层欺骗了。
而且您不希望您的实体模型必须了解基础设施实施。