6

我有一棵Zone对象树:

class Zone {
    protected $parent;

    public function __construct(Zone $parent) {
        $this->parent = $parent;
    }
}

Zone中没有 childrennordescendants属性,因为我想避免在域模型中管理这些关系的痛苦。

相反,域服务在数据库中维护一个闭包表,以将一个区域映射到它的所有后代,在任何级别。

现在,我有一个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;
    }
}

这是一个好的做法,或者如果不是,那么正确的选择是什么?

4

1 回答 1

4

Zone 中没有 children 和 descendants 属性,因为我想避免在域 模型中管理这些关系的痛苦。

相反,域服务在数据库中维护一个闭包表,以将区域映射到任何级别的所有后代。

我添加了一些重点,因为它似乎有点矛盾。您不希望域中的“痛苦”,但您在域服务中管理关闭表。您需要将服务注入实体的事实有时表明可以改进设计。

看起来你有一个区域的层次结构。这似乎是您域的重要组成部分。区域有父母和后代,所以也许你应该相应地对其进行建模。管理关系的痛苦是“正当的”痛苦,因为你这样做是为了模型的表现力。在这种情况下,域驱动设计。因此区域本身将具有以下内容:

zone->hasDescendant($newZone)

而且您不需要注入服务。事实上,您根本不需要服务。因为这项服务的唯一原因是维护闭包表。这不是一个领域问题,只是一个持久性问题。

如果由于某些原因您仍然需要服务,最好将其注入 Zone 类。这样,问题就在更接近源头的地方得到解决。

于 2011-09-19T19:47:50.853 回答