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)
然后我也推导出两个业务逻辑(不变)
- 当用户添加时
Account
必须进行登录验证。
- 当用户更改时
LoginAccount
必须进行登录验证。
我的问题是,对于第一个不变量,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);
}
...
我有一个维护其他系统(媒体)帐户的域。
一开始,我导出了如下聚合根
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
然后我也推导出两个业务逻辑(不变)
- 当用户添加时
Account
必须进行登录验证。 - 当用户更改时
LoginAccount
必须进行登录验证。
我的问题是,对于第一个不变量,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);
}
...