银行转账
银行转账
事务脚本
这里以银行转账事务脚本实现为例,在事务脚本的实现中,关于在两个账号之间转账的领域业务逻辑都被写在了 MoneyTransferService 的实现里面了,而 Account 仅仅是 getters 和 setters 的数据结构,也就是我们说的贫血模型:
public class MoneyTransferServiceTransactionScriptImpl
implements MoneyTransferService {
private AccountDao accountDao;
private BankingTransactionRepository bankingTransactionRepository;
. . .
@Override
public BankingTransaction transfer(
String fromAccountId, String toAccountId, double amount) {
Account fromAccount = accountDao.findById(fromAccountId);
Account toAccount = accountDao.findById(toAccountId);
// . . .
double newBalance = fromAccount.getBalance() - amount;
switch (fromAccount.getOverdraftPolicy()) {
case NEVER:
if (newBalance < 0) {
throw new DebitException("Insufficient funds");
}
break;
case ALLOWED:
if (newBalance < -limit) {
throw new DebitException(
"Overdraft limit (of " + limit + ") exceeded: " + newBalance);
}
break;
}
fromAccount.setBalance(newBalance);
toAccount.setBalance(toAccount.getBalance() + amount);
BankingTransaction moneyTransferTransaction =
new MoneyTranferTransaction(fromAccountId, toAccountId, amount);
bankingTransactionRepository.addTransaction(moneyTransferTransaction);
return moneyTransferTransaction;
}
}
这完全是面向过程的代码风格。
DDD
如果用 DDD 的方式实现,Account 实体除了账号属性之外,还包含了行为和业务逻辑,比如 debit() 和 credit() 方法。
// @Entity
public class Account {
// @Id
private String id;
private double balance;
private OverdraftPolicy overdraftPolicy;
// . . .
public double balance() {
return balance;
}
public void debit(double amount) {
this.overdraftPolicy.preDebit(this, amount);
this.balance = this.balance - amount;
this.overdraftPolicy.postDebit(this, amount);
}
public void credit(double amount) {
this.balance = this.balance + amount;
}
}
而且透支策略 OverdraftPolicy 也不仅仅是一个 Enum 了,而是被抽象成包含了业务规则并采用了策略模式的对象。
public interface OverdraftPolicy {
void preDebit(Account account, double amount);
void postDebit(Account account, double amount);
}
public class NoOverdraftAllowed implements OverdraftPolicy {
public void preDebit(Account account, double amount) {
double newBalance = account.balance() - amount;
if (newBalance < 0) {
throw new DebitException("Insufficient funds");
}
}
public void postDebit(Account account, double amount) {}
}
public class LimitedOverdraft implements OverdraftPolicy {
private double limit;
// . . .
public void preDebit(Account account, double amount) {
double newBalance = account.balance() - amount;
if (newBalance < -limit) {
throw new DebitException(
"Overdraft limit (of " + limit + ") exceeded: " + newBalance
);
}
}
public void postDebit(Account account, double amount) {}
}
而 Domain Service 只需要调用 Domain Entity 对象完成业务逻辑即可。
public class MoneyTransferServiceDomainModelImpl
implements MoneyTransferService {
private AccountRepository accountRepository;
private BankingTransactionRepository bankingTransactionRepository;
. . .
@Override
public BankingTransaction transfer(
String fromAccountId, String toAccountId, double amount) {
Account fromAccount = accountRepository.findById(fromAccountId);
Account toAccount = accountRepository.findById(toAccountId);
// . . .
fromAccount.debit(amount);
toAccount.credit(amount);
BankingTransaction moneyTransferTransaction =
new MoneyTranferTransaction(fromAccountId, toAccountId, amount);
bankingTransactionRepository.addTransaction(moneyTransferTransaction);
return moneyTransferTransaction;
}
}