先看看结构图:
为了实现购买功能,需要增加两个新实体:Snack零食和Slot零食槽
Snack类只有name字段,Slot实体链接Snack和SnackMachine,同时也包含自身信息:位置,价格和数量。
package com.lugew.springbootddd;import lombok.Getter;import lombok.Setter;/*** @author 夏露桂* @since 2021/6/16 10:45*/@Getter@Setterpublic class Snack extends Entity {private String name;public Snack() {}public Snack(String name) {this.name = name;}}
显然,Snack是实体。另一个实体是Slot:
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 Snack snack;private int quantity;private float price;private SnackMachine snackMachine;private int position;public Slot() {}public Slot(SnackMachine snackMachine, int position, Snack snack, int quantity,float price) {this.snackMachine = snackMachine;this.position = position;this.snack = snack;this.quantity = quantity;this.price = price;}}
此时,重构测试方法money_in_transaction_goes_to_money_inside_after_purchase至buySnack_trades_inserted_money_for_a_snack:
@Testpublic void buySnack_trades_inserted_money_for_a_snack() {SnackMachine snackMachine = new SnackMachine();snackMachine.loadSnacks(1, new Snack("Some snack"), 10, 1);snackMachine.insertMoney(Dollar);snackMachine.buySnack(1);assertEquals(snackMachine.getMoneyInTransaction(),0);assertEquals(snackMachine.getMoneyInside().getAmount(), 1, 0.5);Slot slot = snackMachine.getSlots().stream().filter(x -> x.getPosition() ==1).findAny().orElse(null);assertEquals(slot.getQuantity(), 9);}
和SnackMachine:
package com.lugew.springbootddd.snackmachine;import com.lugew.springbootddd.Entity;import com.lugew.springbootddd.Slot;import com.lugew.springbootddd.Snack;import com.lugew.springbootddd.SnackMachineDto;import lombok.Getter;import lombok.Setter;import java.util.Arrays;import java.util.List;import static com.lugew.springbootddd.snackmachine.Money.None;@Getter@Setterpublic final class SnackMachine extends Entity {private Money moneyInside;private Money moneyInTransaction;private List<Slot> slots;public SnackMachine() {moneyInside = None;moneyInTransaction = None;slots = new ArrayList<>();slots.add(new Slot(this, 1, null, 0, 1));slots.add(new Slot(this, 2, null, 0, 1));slots.add(new Slot(this, 3, null, 0, 1));}public void insertMoney(Money money) {Money[] coinsAndNotes = {Money.Cent, Money.TenCent, Money.Quarter,Money.Dollar, Money.FiveDollar,Money.TwentyDollar};if (!Arrays.asList(coinsAndNotes).contains(money))throw new IllegalStateException();moneyInTransaction = Money.add(moneyInTransaction, money);}public void returnMoney() {moneyInTransaction = None;}public void buySnack(int position) {Slot slot = slots.stream().filter(x -> x.getPosition() ==position).findAny().orElse(null);slot.setQuantity(slot.getQuantity() - 1);moneyInside = Money.add(moneyInside, moneyInTransaction);moneyInTransaction = None;}public SnackMachineDto convertToSnackMachineDto() {SnackMachineDto snackMachineDto = new SnackMachineDto();snackMachineDto.setId(id);snackMachineDto.setMoneyInTransaction(moneyInTransaction.getAmount());snackMachineDto.setOneCentCount(moneyInside.getOneCentCount());snackMachineDto.setTenCentCount(moneyInside.getTenCentCount());snackMachineDto.setQuarterCount(moneyInside.getQuarterCount());snackMachineDto.setOneDollarCount(moneyInside.getOneDollarCount());snackMachineDto.setFiveDollarCount(moneyInside.getFiveDollarCount());snackMachineDto.setTwentyDollarCount(moneyInside.getTwentyDollarCount());return snackMachineDto;}public void loadSnacks(int position, Snack snack, int quantity, float price) {Slot slot = slots.stream().filter(x -> x.getPosition() ==position).findAny().orElse(null);if (slot != null) {slot.setSnack(snack);slot.setQuantity(quantity);slot.setPrice(price);}}}
此外,还有SnackMachineController:
package com.lugew.springbootddd;import com.lugew.springbootddd.snackmachine.Money;import com.lugew.springbootddd.snackmachine.SnackMachine;import lombok.RequiredArgsConstructor;import org.springframework.web.bind.annotation.*;import static com.lugew.springbootddd.snackmachine.Money.*;/*** @author 夏露桂* @since 2021/6/10 11:55*/@RestController@RequestMapping("snackmachines")@RequiredArgsConstructorpublic class SnackMachineController {private final SnackMachineRepository snackMachineRepository;@GetMapping("/{id}")@ResponseBodypublic SnackMachineDto getSnackMachine(@PathVariable("id") long id) {return snackMachineRepository.findById(id).orElse(null);}@PutMapping("/{id}/{slotNumber}")public void buySnack(@PathVariable("id") long id, @PathVariable("slotNumber")int slotNumber) {SnackMachineDto snackMachineDto =snackMachineRepository.findById(id).orElse(null);SnackMachine snackMachine = snackMachineDto.convertToSnackMachine();snackMachine.buySnack(slotNumber);snackMachineRepository.save(snackMachine.convertToSnackMachineDto());}@PutMapping("/{id}/moneyInTransaction/{coinOrNote}")public void insertCoinOrNote(@PathVariable("id") long id, @PathVariable("coinOrNote") String coinOrNote) {SnackMachineDto snackMachineDto =snackMachineRepository.findById(id).orElse(null);SnackMachine snackMachine = snackMachineDto.convertToSnackMachine();if (coinOrNote.equalsIgnoreCase("Cent")) snackMachine.insertMoney(Cent);else if (coinOrNote.equalsIgnoreCase("TenCent"))snackMachine.insertMoney(TenCent);else if (coinOrNote.equalsIgnoreCase("Quarter"))snackMachine.insertMoney(Quarter);else if (coinOrNote.equalsIgnoreCase("Dollar"))snackMachine.insertMoney(Dollar);else if (coinOrNote.equalsIgnoreCase("FiveDollar"))snackMachine.insertMoney(FiveDollar);else if (coinOrNote.equalsIgnoreCase("TwentyDollar"))snackMachine.insertMoney(TwentyDollar);snackMachineRepository.save(snackMachine.convertToSnackMachineDto());}@PutMapping("/{id}/moneyInTransaction")public void returnMoney(@PathVariable("id") long id) {SnackMachineDto snackMachineDto =snackMachineRepository.findById(id).orElse(null);SnackMachine snackMachine = snackMachineDto.convertToSnackMachine();snackMachine.returnMoney();snackMachineRepository.save(snackMachine.convertToSnackMachineDto());}public Money getWholeMoney(SnackMachine snackMachine) {return Money.add(snackMachine.getMoneyInside(), snackMachine.getMoneyInTransaction());}}
查看测试:
buySnack功能的缺陷先不谈,说说设计模式。
