DDD:将服务注入实体可以吗

发布于 2024-12-05 09:18:11 字数 1188 浏览 6 评论 0原文

我有一个 Zone 对象树:

class Zone {
    protected Zone $parent;

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

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

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

现在,我有一个可以分配一个或多个区域的用户

class User {
    protected array $zones;

    public function assignZone(Zone $zone) {
        $this->zones[] = $zone;
    }
}

我的问题是,在向用户分配新区域之前,我想检查该区域是否尚未分配,通过其后代之一显式或隐式。

因此,我希望我的控制器将服务暂时注入到此方法中,以执行必要的检查:

class User {
    protected array $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;
    }
}

这是一个好的做法吗?如果不是,正确的替代方案是什么?

I have a tree of Zone objects:

class Zone {
    protected Zone $parent;

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

There are no children nor descendants property in the Zone, because I want to avoid the pain of managing these relationships in the domain model.

Instead, a domain service maintains a closure table in the database, to map a zone to all its descendants, at any level.

Now, I have a User which can be assigned one or more Zones:

class User {
    protected array $zones;

    public function assignZone(Zone $zone) {
        $this->zones[] = $zone;
    }
}

My problem is that, prior to assigning a new Zone to the User, I'd like to check that this Zone is not already assigned, either explicitly or implicitly via one of its descendants.

Therefore I'd like my controller to transiently inject the Service into this method, to perform the necessary checks:

class User {
    protected array $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;
    }
}

Is that a good practice, or if not, what's the correct alternative?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

债姬 2024-12-12 09:18:11

该区域没有子女或后代财产,因为我
希望避免管理域中这些关系的痛苦
型号。

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

我加了一些强调,因为这看起来有点矛盾。您不希望域中出现“痛苦”,但您可以在域服务中管理闭包表。有时需要将服务注入实体这一事实表明设计可以改进。

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

zone->hasDescendant($newZone)

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

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

There are no children nor descendants property in the Zone, because I
want to avoid the pain of managing these relationships in the domain
model.

Instead, a domain service maintains a closure table in the database,
to map a zone to all its descendants, at any level.

I added some emphasis because it seems a bit contradictory. You don't want the 'pain' in domain, yet you manage closure table in domain service. The fact that you need to inject service into entity sometimes indicates that design can be improved.

It looks like you have a hierarchy of Zones. This seem to be an important part of your domain. Zones have parent and descendants so maybe you should model it accordingly. Pain of managing the relationship is a 'justified' pain because you doing it for the sake of model expressiveness. The domain drives the design in this case. So zone itself will have something like:

zone->hasDescendant($newZone)

And you would not need to inject a service. In fact you would not need a service at all. Because the only reason for this service is maintaining closure table. Which is not a domain concern and is just a persistence issue.

If for some reasons you still need service it might be better to inject it into Zone class. This way the problem is solved closer to its source.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文