限界上下文已经定义了,接下来是实现追踪用户银行卡手续费,首先是ApllicationService的AtmController:

    1. @PutMapping("/{id}/{amount}")
    2. @ResponseBody
    3. public String takeMoney(@PathVariable("id") long id, @PathVariable("amount")
    4. float amount) {
    5. AtmDto atmDto = atmRepository.findById(id).orElse(null);
    6. Atm atm = atmDto.convertToAtm();
    7. if (!atm.canTakeMoney(amount).isEmpty()) return
    8. atm.canTakeMoney(amount);
    9. float amountWithCommission =
    10. atm.calculateAmountWithCommission(amount);
    11. paymentGateway.chargePayment(amountWithCommission);
    12. atm.takeMoney(amount);
    13. atmRepository.save(atm.convertToAtmDto());
    14. HeadOffice headOffice = getHeadOfficeInstance();
    15. headOffice.setBalance(headOffice.getBalance() + amountWithCommission);
    16. officeRepository.save(headOffice);
    17. return "You have withrawn amount : $" + amount;
    18. }

    通过officeRepository进行手续费累加,这种方式有几个缺点:一,AtmController和HeadOffice紧耦合,ATM和Management限界上下文相互依赖;二,代码重复,如果其它位置需要扣除手续费的话势必要重复编码。第二种方式是在Atm类中执行相关逻辑:

    1. public void takeMoney(float amount, HeadOffice headOffice) {
    2. if (!canTakeMoney(amount).equals("")) {
    3. throw new IllegalStateException();
    4. }
    5. Money output = moneyInside.allocate(amount);
    6. moneyInside = moneyInside.substract(output);
    7. float amountWithCommission = calculateAmountWithCommission(amount);
    8. moneyCharged += amountWithCommission;
    9. headOffice.setBalance(headOffice.getBalance() + amountWithCommission);
    10. }

    这种方式也许可以消除代码重复问题,但会带来其它问题:第一,两个限界上下文依旧紧耦合;第二,ATM中出现了其职责外的事件,这显然违背了单职责原则。如何解决?使用领域事件——ATM实体在取款时产生口扣费事件。Management界限上下文订阅事件,改变手续费字段。使用这种方式既避免了代码紧耦合,也消除了冗余代码。