先看看结构图:
为了实现购买功能,需要增加两个新实体: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
@Setter
public 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
@Setter
public 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:
@Test
public 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
@Setter
public 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")
@RequiredArgsConstructor
public class SnackMachineController {
private final SnackMachineRepository snackMachineRepository;
@GetMapping("/{id}")
@ResponseBody
public 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功能的缺陷先不谈,说说设计模式。