我有一个Zone
个对象的树:
class Zone {
protected $parent;
public function __construct(Zone $parent) {
$this->parent = $parent;
}
}
区域中有没有 children
或descendants
属性,因为我想避免在域模型中管理这些关系的痛苦。
相反,域服务在数据库中维护一个闭包表,以便在任何级别将区域映射到其所有后代。
现在,我有一个User
可以分配一个或多个区域:
class User {
protected $zones;
public function assignZone(Zone $zone) {
$this->zones[] = $zone;
}
}
我的问题是,在为用户分配新区域之前,我想检查是否已经通过其后代明确或隐式地分配了该区域。
因此,我希望我的控制器能够将服务暂时注入此方法,以执行必要的检查:
class User {
protected $zones;
public function assignZone(Zone $newZone, ZoneService $zoneService) {
foreach ($this->zones as $zone) {
if ($service->zoneHasDescendant($zone, $newZone)) {
throw new Exception('The user is already assigned this zone');
}
}
$this->zones[] = $zone;
}
}
这是一个好习惯,或者如果不是,那么正确的选择是什么?
答案 0 :(得分:3)
区内没有儿童或后代财产,因为我 希望避免在域中管理这些关系的痛苦 模型。
相反,域服务在数据库中维护一个闭包表, 将区域映射到任何级别的所有后代。
我增加了一些重点,因为它看起来有点矛盾。您不希望域中的“痛苦”,但您在域服务中管理关闭表。您需要将服务注入实体这一事实有时表明可以改进设计。
看起来你有一个区域层次结构。这似乎是您域名的重要组成部分。区域有父级和后代,所以也许你应该相应地建模它。管理这种关系的痛苦是一种“合理的”痛苦,因为你为了模特表达而这样做。在这种情况下,域驱动设计。区域本身将具有如下内容:
zone->hasDescendant($newZone)
你不需要注入服务。事实上,你根本不需要服务。因为这项服务的唯一原因是维护闭包表。这不是域名关注,只是一个持久性问题。
如果由于某些原因您还需要服务,最好将其注入Zone类。这样就可以在更接近其来源的情况下解决问题。