现在我们开始实现第二个限界上下文——ATM。它要比SnackMachine要简单,只有取款和手续费等的功能。在这里,我们选择第一种代码隔离类型。

    1. package com.lugew.springbootddd.atm;
    2. import com.lugew.springbootddd.common.AggregateRoot;
    3. import com.lugew.springbootddd.sharedkernel.Money;
    4. import lombok.Getter;
    5. import lombok.Setter;
    6. import static com.lugew.springbootddd.sharedkernel.Money.None;
    7. @Getter
    8. @Setter
    9. public class Atm extends AggregateRoot {
    10. private static float commissionRate = 0.01f;
    11. private Money moneyInside = None;
    12. private float moneyCharged;
    13. public void takeMoney(float amount) {
    14. Money output = moneyInside.allocate(amount);
    15. moneyInside = moneyInside.substract(output);
    16. float amountWithCommission = amount + amount * commissionRate;
    17. moneyCharged += amountWithCommission;
    18. }
    19. public void loadMoney(Money money) {
    20. moneyInside = moneyInside.add(money);
    21. }
    22. }

    显然ATM是聚合根,它包含三个字段moneyInsidemoneyCharged,和takeMoney取款和loadMoney存款方法。接下来为其添加测试

    1. package com.lugew.springbootddd.atm;
    2. import org.junit.Test;
    3. import static com.lugew.springbootddd.sharedkernel.Money.Dollar;
    4. import static org.junit.jupiter.api.Assertions.assertEquals;
    5. public class AtmTest {
    6. @Test
    7. public void take_money_exchanges_money_with_commission() {
    8. Atm atm = new Atm();
    9. atm.loadMoney(Dollar);
    10. atm.takeMoney(1);
    11. assertEquals(atm.getMoneyInside().getAmount(), 0, 0);
    12. assertEquals(atm.getMoneyCharged(), 1.01, 0.001);
    13. }
    14. }

    测试验证取款功能,且取款手续费为0.01。除此之外,还有其它需求,如取款0.01如何处理,取款1.10手续费是0.01还是0.02,这些需求可以咨询领域专家。假设手续费最低0.01且四舍五入计算。

    1. @Test
    2. public void commission_is_at_least_one_cent() {
    3. Atm atm = new Atm();
    4. atm.loadMoney(Cent);
    5. atm.takeMoney(0.01f);
    6. assertEquals(atm.getMoneyCharged(), 0.02, 0.001);
    7. }
    8. @Test
    9. public void commission_is_rounded_up_to_the_next_cent() {
    10. Atm atm = new Atm();
    11. atm.loadMoney(Dollar.add(TenCent));
    12. atm.takeMoney(1.1f);
    13. assertEquals(atm.getMoneyCharged(), 1.12, 0.01);
    14. }
    1. public void takeMoney(float amount) {
    2. Money output = moneyInside.allocate(amount);
    3. moneyInside = moneyInside.substract(output);
    4. float amountWithCommission = calculateAmountWithCommission(amount);
    5. moneyCharged += amountWithCommission;
    6. }
    7. public void loadMoney(Money money) {
    8. moneyInside = moneyInside.add(money);
    9. }
    10. public float calculateAmountWithCommission(float amount) {
    11. float commission = amount * commissionRate;
    12. float lessThanCent = commission % 0.01f;
    13. if (lessThanCent > 0) {
    14. commission = commission - lessThanCent + 0.01f;
    15. }
    16. return amount + commission;
    17. }

    还需添加一些验证:

    1. public void takeMoney(float amount) {
    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. }
    10. public String canTakeMoney(float amount) {
    11. if (amount <= 0f)
    12. return "Invalid amount";
    13. if (moneyInside.getAmount() < amount)
    14. return "Not enough money";
    15. if (!moneyInside.canAllocate(amount))
    16. return "Not enough change";
    17. return "";
    18. }