现在我们开始实现第二个限界上下文——ATM。它要比SnackMachine要简单,只有取款和手续费等的功能。在这里,我们选择第一种代码隔离类型。
package com.lugew.springbootddd.atm;
import com.lugew.springbootddd.common.AggregateRoot;
import com.lugew.springbootddd.sharedkernel.Money;
import lombok.Getter;
import lombok.Setter;
import static com.lugew.springbootddd.sharedkernel.Money.None;
@Getter
@Setter
public class Atm extends AggregateRoot {
private static float commissionRate = 0.01f;
private Money moneyInside = None;
private float moneyCharged;
public void takeMoney(float amount) {
Money output = moneyInside.allocate(amount);
moneyInside = moneyInside.substract(output);
float amountWithCommission = amount + amount * commissionRate;
moneyCharged += amountWithCommission;
}
public void loadMoney(Money money) {
moneyInside = moneyInside.add(money);
}
}
显然ATM是聚合根,它包含三个字段moneyInside
和moneyCharged
,和takeMoney
取款和loadMoney
存款方法。接下来为其添加测试
package com.lugew.springbootddd.atm;
import org.junit.Test;
import static com.lugew.springbootddd.sharedkernel.Money.Dollar;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class AtmTest {
@Test
public void take_money_exchanges_money_with_commission() {
Atm atm = new Atm();
atm.loadMoney(Dollar);
atm.takeMoney(1);
assertEquals(atm.getMoneyInside().getAmount(), 0, 0);
assertEquals(atm.getMoneyCharged(), 1.01, 0.001);
}
}
测试验证取款功能,且取款手续费为0.01
。除此之外,还有其它需求,如取款0.01如何处理,取款1.10手续费是0.01还是0.02,这些需求可以咨询领域专家。假设手续费最低0.01且四舍五入计算。
@Test
public void commission_is_at_least_one_cent() {
Atm atm = new Atm();
atm.loadMoney(Cent);
atm.takeMoney(0.01f);
assertEquals(atm.getMoneyCharged(), 0.02, 0.001);
}
@Test
public void commission_is_rounded_up_to_the_next_cent() {
Atm atm = new Atm();
atm.loadMoney(Dollar.add(TenCent));
atm.takeMoney(1.1f);
assertEquals(atm.getMoneyCharged(), 1.12, 0.01);
}
public void takeMoney(float amount) {
Money output = moneyInside.allocate(amount);
moneyInside = moneyInside.substract(output);
float amountWithCommission = calculateAmountWithCommission(amount);
moneyCharged += amountWithCommission;
}
public void loadMoney(Money money) {
moneyInside = moneyInside.add(money);
}
public float calculateAmountWithCommission(float amount) {
float commission = amount * commissionRate;
float lessThanCent = commission % 0.01f;
if (lessThanCent > 0) {
commission = commission - lessThanCent + 0.01f;
}
return amount + commission;
}
还需添加一些验证:
public void takeMoney(float amount) {
if (!canTakeMoney(amount).equals("")) {
throw new IllegalStateException();
}
Money output = moneyInside.allocate(amount);
moneyInside = moneyInside.substract(output);
float amountWithCommission = calculateAmountWithCommission(amount);
moneyCharged += amountWithCommission;
}
public String canTakeMoney(float amount) {
if (amount <= 0f)
return "Invalid amount";
if (moneyInside.getAmount() < amount)
return "Not enough money";
if (!moneyInside.canAllocate(amount))
return "Not enough change";
return "";
}