2

我目前正在研究一个由几个有界上下文组成的 DDD 系统。其中2个是:

  1. 上下文“账户管理”:只允许工作人员在这里工作。这个想法是管理客户帐户(如地址、电话号码、联系人等)并验证客户的帐户(基本上检查客户提供的数据是否有效)。
  2. 上下文“网站”:我可以作为客户登录并编辑我的数据(例如更改我的地址)

这是问题:

根据定义,登录到帐户管理上下文的用户是员工。所以我可以假设这里所做的更改在“数据已验证”的意义上是“值得信赖的”。appservice 的简化变体如下所示:

class AccountAppService
{
    public function changeAddress(string $accountId, string $address) : void
    {
        $account = $this->accountRepository->ofId(new Guid($accountId));
        $account->changeAddress(new Address($address));
    }
{

这是我在员工更改地址时调用的 appservice。请注意,我没有注入/使用 IdentityService 来了解员工是谁,因为这在这里并不有趣。Account 实体在成功调用其 changeAddress() 方法后会发出一个 AccountAddressChanged 事件,如下所示

class Account implements Entity
{
    public function changeAddress(Address $address) : void
    {
        $this->address = $address;
        DomainEventSubscriber::instance()->publish(new AccountAddressChanged($this));
    }
}

但是,一旦客户在网站上编辑数据,我还需要反映更改。我计划通过“AccountAddressChangedViaWebsite”事件来异步执行此操作。帐户管理上下文将订阅并处理该事件,将相应的帐户再次设置为“未验证”。因此,帐户管理上下文的简化订阅者可能如下所示:

class AccountAddressChangedViaWebsiteSubscriber
{
    public function handle(AccountAddressChangedViaWebsite $event) : void
    {
        $accountId = $event->accountId();
        $address = $event->getAddress();
        $this->accountService->changeAddress($accountId, $address);
    }
}

现在的问题是:员工直接调用应用服务,客户通过订阅者。如果我们说“我们必须在客户更新他的数据后重新验证一个帐户”,这听起来像是一个域概念。领域概念适合实体或领域服务,但不适合我所知道的应用程序服务或订阅者。这对我来说意味着应该避免以下情况(注意最后一行调用 unverifyAccount()):

class AccountAddressChangedViaWebsiteSubscriber
{
    public function handle(AccountAddressChangedViaWebsite $event) : void
    {
        $accountId = $event->accountId();
        $address = $event->getAddress();
        $this->accountService->changeAddress($accountId, $address);
        $this->accountService->unverifyAccount($accountId);
    }
}

这是有点隐藏在订阅者中的域逻辑,这看起来很奇怪。我有直觉认为这应该是域服务的责任,但是域服务如何知道它是由外部事件(通过订阅者)或命令调用的?

我可以传递一种“发起者”ValueObject,它告诉我造成这种情况的用户是员工还是外部系统。例子:

class OriginatorService
{
    public function changeAddress(Originator $originator, Account $account, Address $address) : void
    {
        $account->changeAddress($address);
        if(($originator instanceof Employee) === false) {
            $account->unverify();
        }
    }
}

在这里,我将要做的事情委托给域服务。但是将 OriginatorService 双重分派到 Account 实体是否是一个好的解决方案?这样,实体可以通过询问传入的 originatorService 来检查是谁导致了更改,并且可以取消验证自己。

我想我会在这里陷入 DDD 兔子洞,但是在这种情况下,您的经验/最佳实践是什么?

4

1 回答 1

2

最简单的答案可能是在您的模型中引入 UnverifiedAddress 作为一个概念,而不是试图将“地址”视为一个普遍的想法,并将验证作为事后的想法。

于 2017-03-10T15:10:14.000 回答