我试图了解如何表示某些DDD(域驱动设计)规则。 按照蓝皮书大会,我们有:
当客户端可以访问内部实体时,我很难找到强制执行不变量的最佳方法。
这个问题当然只会在子实体可变的情况下发生。
将此玩具示例设置为Car
,其中包含四个Tire
(s)。我想要依次跟踪每个Tire
的使用情况。
显然Car
是聚合根而Tire
是儿童实体。
商家规则:无法将Milage添加到单个
时,Milage只能添加到所有4个轮胎中Tire
。当连接到Car
天真实施将是:
public class Tire
{
public double Milage { get; private set; }
public DateTime PurchaseDate { get; set; }
public string ID { get; set; }
public void AddMilage(double milage) => Milage += milage;
}
public class Car
{
public Tire FrontLefTire { get; private set; }
public Tire FrontRightTire { get; private set; }
public Tire RearLeftTire { get; private set; }
public Tire RearRightTire { get; private set; }
public void AddMilage (double milage)
{
FrontLefTire.AddMilage(milage);
FrontRightTire.AddMilage(milage);
RearLeftTire.AddMilage(milage);
RearRightTire.AddMilage(milage);
}
public void RotateTires()
{
var oldFrontLefTire = FrontLefTire;
var oldFrontRightTire = FrontRightTire;
var oldRearLeftTire = RearLeftTire;
var oldRearRightTire = RearRightTire;
RearRightTire = oldFrontLefTire;
FrontRightTire = oldRearRightTire;
RearLeftTire = oldFrontRightTire;
FrontLefTire = oldRearLeftTire;
}
//...
}
但是Tire.AddMilage
方法是公开的,这意味着任何服务都可以执行以下操作:
Car car = new Car(); //...
// Adds Milage to all tires, respecting invariants - OK
car.AddMilage(200);
//corrupt access to front tire, change milage of single tire on car
//violating business rules - ERROR
car.FrontLefTire.AddMilage(200);
我想到了可能的解决方案:
events
上创建Tire
以验证更改,并在Car
上实施Car
成为Tire
的工厂,在其构造函数上传递 TireState
,并持有对它的引用。但我觉得应该有一种更简单的方法来做到这一点。
您怎么看?
答案 0 :(得分:1)
可以传递对内部成员的瞬时引用,仅用于单个操作。
自蓝皮书撰写以来,这种做法已经发生了变化;传递对支持变异操作的内部成员的引用尚未完成。
考虑这一点的方法是采用聚合API(当前支持查询和命令),并将该API拆分为两个(或更多)接口;一个支持命令操作,另一个支持查询。
命令操作仍然遵循通常的模式,提供应用程序可以让聚合自行更改的路径。
查询操作返回包含 no 变异操作的接口,既不直接也不代理。
root.getA() // returns an A API with no mutation operations
root.getA().getB() // returns a B API with no mutation operations
查询一直是查询。
在大多数情况下,您可以避免完全查询实体;而是返回表示实体当前状态的值。
避免共享子实体的另一个原因是,在大多数情况下,选择将聚合的该部分建模为单独的实体是您可能希望在域模型中更改的决策。通过在API中公开实体,您将在该实现选择与API的使用者之间创建耦合。
(考虑到这一点的一种方式:汽车集合不是'汽车"它是'文件"描述"汽车" 34; API应该将应用程序与文档的特定细节隔离开来。)
答案 1 :(得分:0)
轮胎应该没有吸气剂。
吸气剂让你陷入困境。删除getter不仅仅是DDD Aggregte Roots的问题,而是OO,Demeter法则等问题。
想一想为什么你需要一辆汽车的轮胎并将这个功能转移到汽车本身。