银行转账

银行转账

事务脚本

这里以银行转账事务脚本实现为例,在事务脚本的实现中,关于在两个账号之间转账的领域业务逻辑都被写在了 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;
  }
}
上一页