DDD:我可以将域服务作为聚合构造函数的参数传递吗

DDD: Can I pass a Domain-Service as a parameter of aggregate constructor

我有一个维护其他系统(媒体)帐户的域。
一开始,我导出了如下聚合根

public class Account extends Entity {
    
    private AccountId accountId;
    private TenantId tenantId;
    private LoginAccount loginAccount;
    private Media media;
    private LoginValidity validity;
    
    
    public Account(TenatId shopId, Media media, LoginAccount loginAccount) {
        this.accountId = new AccountId(); 
        this.setTenatId(shopId);
        this.set(media);
        this.setLoginValidity(LoginValidity.NOT_REQUESTED);
    }
    
    
    public void validateLogin(LoginValidationService loginValidationService) {
        LoginValidity validity = loginValidationService.validateLoginFor(media,loginAccount);
        setLoginValidity(validity);
        
        //TO-DO EVENT PUBLISHING
    }
    
    public void changeLoginAccount(LoginAccount loginAccount) {
        setLoginAccount(loginAccount);
        setLoginValidity(LoginValidity.NOT_REQUESTED);
        
        //TO-DO EVENT PUBLISHING?
    }

    ...Setters
}

而且我还派生了 LoginValidationService 作为域服务。
LoginValidationService 使用 Media

确定策略(policy)

然后我也推导出两个业务逻辑(不变)

我的问题是,对于第一个不变量,LoginValidationService(域服务)可以像这样作为聚合根构造函数的参数

public class AccountApplicationService {
   private LoginValidationService loginValidationService;
   private AccountRepository accountRepository;

   public Account createAccount(CreateAccountCommand command) {
        TenantId tenantId = new TenantId(command.getTenantId());
        Media media = mediaService.mediaFrom(command.getMediaId());
        
        Account account = new Account(tenantId, 
                                     media,
                                     command.getLoginAccount(),
                                     loginValidationService);
        
        accountRepository.save(account);
        return ccount;
   }
   ...
}
public class Account extends Entity {
    
    private AccountId accountId;
    private TenantId tenantId;
    private LoginAccount loginAccount;
    private Media media;
    private LoginValidity validity;
    
    public Account(TenatId shopId, 
                   Media media, 
                   LoginAccount 
                   loginAccount,LoginValidationService loginValidationService) {

        this.accountId = new AccountId(); 
        this.setTenatId(shopId);
        this.set(media);
        LoginValidity validity =
                 loginValidationService.validateLoginFor(media,loginAccount);
        this.setLoginValidity(validity);
    }
   .... 
}

是否存在上述模式? (将域服务传递给构造函数)这是 DDD 的正确方法吗?

我是否必须将第一个不变量导出为 用例?像这样,

public class AccountApplicationService {
   private LoginValidationService loginValidationService;
   private AccountRepository accountRepository;

    public Account createAccountAndValidateLogin(CreateAccountAndValidateLoginCommand command) {
        TenantId tenantId = new TenantId(command.getTenantId());
        Media media = mediaService.mediaFrom(command.getMediaId());
        
        MediaAccount mediaAccount = new MediaAccount(tenantId,media,command.getLoginAccount());
        mediaAccount.validateLogin(loginValidationService);
        
        mediaAccountRepository.save(mediaAccount);
    }
   ...
}

请多多指教

------------编辑--------
我添加了帐户的构造函数代码。 LoginValidationService 不是帐户的成员。

Can I pass a Domain-Service as a parameter of aggregate constructor

是的,但我希望从长远来看,这会让您的生活变得更加艰难 运行。

An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. -- Evans, 2003

然而,域服务不会改变——它们是无状态的,并且“任何客户端都可以使用特定服务的任何实例,而无需考虑实例的个人历史。”

所以以这种方式混合模式在两个方面有点奇怪;将服务作为聚合的成员包括在内表明它发生了变化,并且还暗示该聚合与服务的特定实例具有特殊关系,这与它们不可互换的概念相矛盾。

我不清楚在将服务嵌入到聚合中的设计中您可以获得什么补偿优势。

LoginValidity 作为 Account 聚合构造函数参数传递是一种解决方案吗?

public Account createAccount(CreateAccountCommand command) {
        TenantId tenantId = new TenantId(command.getTenantId());
        Media media = mediaService.mediaFrom(command.getMediaId());
        LoginValidity loginValidity = 
            loginValidationService.validateLoginFor(media,command.getLoginAccount());

        Account account = new Account(tenantId, 
                                     media,
                                     command.getLoginAccount(),
                                     loginValidity);
        
        accountRepository.save(account);
        return ccount;
}

我认为验证帐户是实体不能自己做的事情,所以很明显是域服务的责任,然后我会在用例流逻辑中看到,或者您可以使用域创建帐户服务负责验证和创建帐户,您将业务逻辑封装在域服务而​​不是用例中。

我发现 Account 的一个附加不变量创建 Account 不能保持自身,所以我导出 AccountProvisionService(域服务)。 Application-Service代码如下

...

public Account createAccount(CreateAccountCommand command) {
        
        return AccountProvisioningService.provisionAccount(
             command.getTenantId(), command.getMediaId(), command.getLoginAccount());
    }


public void changeLoginAccount(ChangeLoginAccountCommand command) {
        Account account = existingAccount(command.getShopId(),command.getAccountId());
        LoginValidity loginValidity = loginValidationService.validateLoginFor(Account.media(), command.getLoginAccount());
        account.changeLoginAccount(command.getLoginAccount(),loginValidity);
        
        AccountRepository.save(account);
    }
...