Snack只有三种类型,不允许出现其它类型:
package com.lugew.springbootddd;import lombok.Getter;import lombok.Setter;/*** @author 夏露桂* @since 2021/6/16 10:45*/@Getter@Setterpublic class Snack extends AggregateRoot {public static Snack None = new Snack(0, "None");public static Snack Chocolate = new Snack(1, "Chocolate");public static Snack Soda = new Snack(2, "Soda");public static Snack Gum = new Snack(3, "Gum");private String name;private Snack(long id, String name) {this.id = id;this.name = name;}public SnackDto convertToSnackDto() {SnackDto snackDto = new SnackDto();snackDto.setId(id);snackDto.setName(name);return snackDto;}}
随后将测试中的new Snack(“Some snack”) 替换为Chocolate。
package com.lugew.springbootddd.snackmachine;import com.lugew.springbootddd.Snack;import com.lugew.springbootddd.SnackPile;import org.junit.jupiter.api.Test;import static com.lugew.springbootddd.snackmachine.Money.*;import static org.junit.jupiter.api.Assertions.assertEquals;import static org.junit.jupiter.api.Assertions.assertThrows;/*** @author 夏露桂* @since 2021/6/9 18:12*/public class SnackMachineTest {@Testpublic void return_money_empties_money_in_transaction() {SnackMachine snackMachine = new SnackMachine();snackMachine.insertMoney(Dollar);snackMachine.returnMoney();assertEquals(snackMachine.getMoneyInTransaction(), 0, 0);}@Testpublic void inserted_money_goes_to_money_in_transaction() {SnackMachine snackMachine = new SnackMachine();snackMachine.insertMoney(Cent);snackMachine.insertMoney(Dollar);assertEquals(snackMachine.getMoneyInTransaction(), 1.01f, 0);}@Testpublic void cannot_insert_more_than_one_coin_or_note_at_a_time() {SnackMachine snackMachine = new SnackMachine();Money twoCent = Money.add(Cent, Cent);assertThrows(IllegalStateException.class, () -> {snackMachine.insertMoney(twoCent);});}@Testpublic void buySnack_trades_inserted_money_for_a_snack() {SnackMachine snackMachine = new SnackMachine();snackMachine.loadSnacks(1, new SnackPile(Snack.Chocolate, 10, 1));snackMachine.insertMoney(Dollar);snackMachine.buySnack(1);assertEquals(snackMachine.getMoneyInTransaction(), Money.None.getAmount());assertEquals(snackMachine.getMoneyInside().getAmount(), 1, 0.5);assertEquals(snackMachine.getSnackPile(1).getQuantity(), 9);}@Testpublic void cannot_make_purchase_when_there_is_no_snacks() {SnackMachine snackMachine = new SnackMachine();assertThrows(IllegalStateException.class, () -> {snackMachine.buySnack(1);});}@Testpublic void cannot_make_purchase_if_not_enough_money_inserted() {SnackMachine snackMachine = new SnackMachine();snackMachine.loadSnacks(1, new SnackPile(Snack.Chocolate, 1, 2));snackMachine.insertMoney(Dollar);assertThrows(IllegalStateException.class, () -> {snackMachine.buySnack(1);});}@Testpublic void snack_machine_returns_money_with_highest_denomination_first() {SnackMachine snackMachine = new SnackMachine();snackMachine.loadMoney(Dollar);snackMachine.insertMoney(Quarter);snackMachine.insertMoney(Quarter);snackMachine.insertMoney(Quarter);snackMachine.insertMoney(Quarter);snackMachine.returnMoney();assertEquals(snackMachine.getMoneyInside().getQuarterCount(), 4);assertEquals(snackMachine.getMoneyInside().getOneDollarCount(), 0);}@Testpublic void after_purchase_change_is_returned() {SnackMachine snackMachine = new SnackMachine();snackMachine.loadSnacks(1, new SnackPile(Snack.Chocolate, 1,0.5f));snackMachine.loadMoney(new Money(0, 10, 0, 0, 0, 0));snackMachine.insertMoney(Dollar);snackMachine.buySnack(1);assertEquals(snackMachine.getMoneyInside().getAmount(), 1.5, 0);assertEquals(snackMachine.getMoneyInTransaction(), 0, 0);}@Testpublic void cannot_buy_snack_if_not_enough_change() {SnackMachine snackMachine = new SnackMachine();snackMachine.loadSnacks(1, new SnackPile(Snack.Chocolate, 1, 0.5f));snackMachine.insertMoney(Dollar);assertThrows(IllegalStateException.class, () -> {snackMachine.buySnack(1);});}}
此外Slot构造器也可以优化:
public class Slot extends Entity {public Slot(SnackMachine snackMachine, int position) {this.snackMachine = snackMachine;this.position = position;this.snackPile = new SnackPile(Snack.None, 0, 0);}}
再次重构:
public class SnackPile extends ValueObject<SnackPile> {public static SnackPile Empty = new SnackPile(Snack.None, 0, 0f);}
最终结果:
package com.lugew.springbootddd;import com.lugew.springbootddd.snackmachine.SnackMachine;import lombok.Getter;import lombok.Setter;/*** @author 夏露桂* @since 2021/6/16 10:47*/@Getter@Setterpublic class Slot extends Entity {private SnackPile snackPile;private SnackMachine snackMachine;private int position;public Slot() {}public Slot(SnackMachine snackMachine, int position) {this.snackMachine = snackMachine;this.position = position;this.snackPile = SnackPile.Empty;}public SlotDto convertToSlotDto() {SlotDto slotDto = new SlotDto();slotDto.setId(id);slotDto.setPosition(position);slotDto.setPrice(snackPile.getPrice());slotDto.setQuantity(snackPile.getQuantity());slotDto.setSnackDto(snackPile.getSnack().convertToSnackDto());return slotDto;}public SnackPile getSnackPile() {return snackPile;}public void setSnackPile(SnackPile snackPile) {this.snackPile = snackPile;}public SnackMachine getSnackMachine() {return snackMachine;}public void setSnackMachine(SnackMachine snackMachine) {this.snackMachine = snackMachine;}public int getPosition() {return position;}public void setPosition(int position) {this.position = position;}}
👆持续迭代在DDD中十分常见。
Snack类型的校验可在集成测试中验证。
