为了账号安全,请及时绑定邮箱和手机立即绑定

创建聚合根及其子对象(实体)的正确流程是什么?

创建聚合根及其子对象(实体)的正确流程是什么?

PHP
哔哔one 2022-10-28 16:26:30
我正在将我的数据驱动设计重构为领域驱动,我对代码的结构有几个问题我有一个User entitynamespace Planner\Domain\Entities;class UserEntity {    private $userId;    private $weight;    private $height;    public function __construct(int $id, float $weight, float $height){        $this->userId = $id;        ...    }}我还有一个Settings entity应该与用户对象创建一起创建的。namespace Planner\Domain\Entities;class SettingsEntity {    private $id;    private $userId;    private $darkTheme;    public function __construct(int $id, int $userId, bool $darkTheme){        $this->id = $id;        $this->userId = $userId;        $this->darkTheme = $darkTheme;    }}Settings 对象不能没有 User 存在,因此 settingsEntity 应该由 User 实体管理。这意味着,用户实体不仅仅是一个实体,它应该是一个聚合根。目前,当用户点击“创建账户”时,App 向 发出 API 请求example.com/user/save,控制器动作将请求对象发送到Planner\Application\Services\UserServicesave 方法。namespace Planner\Application\Services;use Planner\Domain\Entities\UserEntity;use Planner\Domain\Entities\SettingsEntity;use Planner\Domain\Repositories\UserRepository;use Planner\Application\Services\SettingsService;class UserService {    public function __construct(UserRepository $repo, SettingsService $settings){        $this->userRepository = $repo;        $this->settingsService = $settings;    }    public function save($request){        $user = new UserEntity(...);        $settings = new SettingsEntity(...);        if(!$this->userRepository->save($user) || !$this->settingsRepository->save($settings)){            throw new UserCreationFailedException();        }    }}问题是,我不知道是否应该一次性创建用户实体和设置实体(从理论上讲,因为我没有用户聚合根,只有一个用户实体)用户聚合根或者当前方式有效。我还有其他需要同时创建的实体...与设置对象相同,我只是将它们添加到ifUserService 保存方法中的检查中(上面的代码)还是应该全部在用户聚合下,例如:namespace Planner\Domain;class User extends AggragateRoot {    public function __construct(UserRepository $repository){        $this->repository = $repository;    }    public function createAccount($request){        $user = new UserEntity(...$request);        $settings = new SettingsEntity(...$user);        $this->repository->save($user, $settings);    }}
查看完整描述

2 回答

?
MYYA

TA贡献1868条经验 获得超4个赞

所有顶级实体都是聚合根。在您当前的设计中,UserEntitySettingsEntity是有效的聚合根 (AR)。AR 是事务性和一致性边界。AR 的作用是确保与它们封装的数据相关的不变量永远不会被破坏,即使通过并发也是如此。

AR 应该设计得尽可能小,因为它们可以防止对它们保护的数据进行并发修改。为了从 AR 模式中受益,您必须努力将 AR 视为事务边界,因此对于大多数用例(可能存在例外),尝试只修改每个事务的单个 AR。但是,该规则在创建 AR 时并不适用,因为在创建时并发冲突不应该是常见的。

这里有两种显而易见的潜在设计,正确的一种取决于实际的业务不变量和您想要做出的妥协。

  1. User并且Settings具有交叉不变量,这意味着不变量User可能取决于状态,Settings反之亦然。在这种情况下User,并且Settings必须是同一一致性边界的一部分。您很可能拥有UserAR 和Settings生活在User.

  2. User并且Settings可以独立进化(除了他们的创造)。在这种情况下,您很可能希望将UserSettings作为自己独立的 AR,但在同一个事务中创建两者(或不创建 - 最终一致性)。请注意,在 AR 上使用工厂方法来创建另一个工厂方法通常很优雅。

    transaction {
         user = new User(…)
         settings = user.initSettings(...)
         userRepository.save(user);
         settingsRepository.save(settings);}

    从那时起,UserSettings在不同的事务中进行修改。

PS:我建议删除诸如“实体”之类的技术前缀。语言是 DDD 的关键,我怀疑领域专家在他们的语言中使用“UserEntity”(甚至可能不是“User”)或“SettingsEntity”这个词。


查看完整回答
反对 回复 2022-10-28
?
温温酱

TA贡献1752条经验 获得超4个赞

这取决于它是否是新用户。

如果它是现有用户,则处理它的一种方法是使用存储库“水合”用户和存储中的设置。然后修改。

如果是新用户,您可以使用工厂实例化聚合根(用户实体)并使用符合 UL 的工厂方法从输入生成设置。

拥有用户对象后,将其发送到存储库以进行持久化。


查看完整回答
反对 回复 2022-10-28
  • 2 回答
  • 0 关注
  • 176 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信