前一篇文章介绍了domain object。这篇文章写一下具体的例子。
假设我们要实现一个账户管理的密码修改功能。
- 密码不能为空
- 密码必须加密(这个功能暂不实现)
修改密码
- 修改密码时必须输入旧密码,旧密码输入正确后才可更改密码。
其实建模是一个过程,而且可能是程序设计里比较难有容易被忽略的过程。就像很多侦探片里的推理一样,推理很难,但往往侦探片只会告诉你答案,而不是告诉你如何推理的。很抱歉我这里也讲不了建模的过程,这回事另一个话题。但大概我们会想到如下的model。
Account aggregate
Account (entity, Account aggregate的root)
因为密码可以更改可以理解为mutable,密码变化后,不代表账号就变成了另一个账号。所以把它定义成entity。
AccountId (value object)
账号id生成后就不可变了。
Password (value object)
密码设置后,密码本身是不可变的。
更改账号密码应该理解为,用新密码换掉账号的旧密码。而非旧密码本身做了变化。
然后对应aggregate,会有AggregateRepository
Account
public class Account {
private AccountId accountId;
private EncryptedPassword encryptedPassword;
public void changePassword(String oldPassword, String newPassword){
if(encryptedPassword.verify(oldPassword)){
throw new IllegalArgumentException("old encryptedPassword is not correct");
}
encryptedPassword = new EncryptedPassword(newPassword);
}
public static Account createAccount(String email, String password){
Account account = new Account();
account.accountId= new Account(email);
account.encryptedPassword = new EncryptedPassword(password);
return account;
}
private Account(){
}
}
AccountId
@AllArgsConstructor
@Getter
public class AccountId {
@NonNull
private String email;
}
用来表示账号id的类。immutable。
EncyptedPassword
public class EncryptedPassword {
private String encryptedPassword;
public EncryptedPassword(@NonNull String password){
if(password.equals("")){
throw new IllegalArgumentException("password cannot be null");
}
// TODO password not encrypted.
this.encryptedPassword = password;
}
public boolean verify(String ps){
return encryptedPassword.equals(ps);
}
}
IAccountRepository
public interface IAccountRepository {
Account findById(String email);
void save(Account account);
}
最后写一下application层的application service(之后的文章会对application service做说明)
AccountApplicationService
public class AccountApplicationService {
@Autowired
private IAccountRepository accountRepository;
@Transactional
public void changePassword(String email, String oldPassword, String newPasssord){
Account account = accountRepository.findById(email);
account.changePassword(oldPassword, newPassword);
accountRepository.save(account);
}
}