重构代码,结合UI、Controller和Repository:
package com.lugew.springbootddd.snackmachine;import com.lugew.springbootddd.Entity;import com.lugew.springbootddd.SnackMachineDto;import lombok.Getter;import lombok.Setter;import java.util.Arrays;import static com.lugew.springbootddd.snackmachine.Money.None;@Getter@Setterpublic final class SnackMachine extends Entity {private Money moneyInside;private Money moneyInTransaction;public SnackMachine() {moneyInside = None;moneyInTransaction = None;}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() {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;}}
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();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());}}
package com.lugew.springbootddd;import com.lugew.springbootddd.snackmachine.Money;import com.lugew.springbootddd.snackmachine.SnackMachine;import lombok.Getter;import lombok.Setter;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;/*** @author 夏露桂* @since 2021/6/10 12:00*/@Getter@Setter@Entitypublic class SnackMachineDto {@Id@GeneratedValueprivate long id;private int oneCentCount;private int tenCentCount;private int quarterCount;private int oneDollarCount;private int fiveDollarCount;private int twentyDollarCount;private float moneyInTransaction;public SnackMachine convertToSnackMachine() {SnackMachine snackMachine = new SnackMachine();snackMachine.setId(id);snackMachine.setMoneyInTransaction(convertAmountToMoney());snackMachine.setMoneyInside(newMoney(oneCentCount, tenCentCount, quarterCount, oneDollarCount, fiveDollarCount, twentyDollarCount));return snackMachine;}private Money convertAmountToMoney() {float amount = this.moneyInTransaction;int twentyDollarCount = (int) (amount / 20f);amount %= 20f;int fiveDollarCount = (int) (amount / 5f);amount %= 5f;int oneDollarCount = (int) (amount);amount %= 1f;int quarterCount = (int) (amount / 0.25f);amount %= 0.25f;int tenCentCount = (int) (amount / 0.10f);amount %= 0.10f;int oneCentCount = (int) (amount / 0.01f);return new Money(this.moneyInTransaction, oneCentCount, tenCentCount, quarterCount, oneDollarCount, fiveDollarCount, twentyDollarCount);}}
package com.lugew.springbootddd.snackmachine;import com.lugew.springbootddd.ValueObject;import lombok.Getter;/*** @author 夏露桂* @since 2021/6/7 11:59*/@Getterpublic class Money extends ValueObject<Money> {public static Money None = new Money(0, 0, 0, 0, 0, 0);public static Money Cent = new Money(1, 0, 0, 0, 0, 0);public static Money TenCent = new Money(0, 1, 0, 0, 0, 0);public static Money Quarter = new Money(0, 0, 1, 0, 0, 0);public static Money Dollar = new Money(0, 0, 0, 1, 0, 0);public static Money FiveDollar = new Money(0, 0, 0, 0, 1, 0);public static Money TwentyDollar = new Money(0, 0, 0, 0, 0, 1);private final int oneCentCount;private final int tenCentCount;private final int quarterCount;private final int oneDollarCount;private final int fiveDollarCount;private final int twentyDollarCount;private float amount;public float getAmount() {return oneCentCount * 0.01f + tenCentCount * 0.10f + quarterCount * 0.25f +oneDollarCount * 1f+ fiveDollarCount * 5f + twentyDollarCount * 20f;}public Money(int oneCentCount, int tenCentCount, int quarterCount, intoneDollarCount, int fiveDollarCount, int twentyDollarCount) {if (oneCentCount < 0)throw new IllegalStateException();if (tenCentCount < 0)throw new IllegalStateException();if (quarterCount < 0)throw new IllegalStateException();if (oneDollarCount < 0)throw new IllegalStateException();if (fiveDollarCount < 0)throw new IllegalStateException();if (twentyDollarCount < 0)throw new IllegalStateException();this.oneCentCount = oneCentCount;this.tenCentCount = tenCentCount;this.quarterCount = quarterCount;this.oneDollarCount = oneDollarCount;this.fiveDollarCount = fiveDollarCount;this.twentyDollarCount = twentyDollarCount;}public Money(float amount, int oneCentCount, int tenCentCount, int quarterCount, intoneDollarCount, int fiveDollarCount, int twentyDollarCount) {this(oneCentCount, tenCentCount, quarterCount, oneDollarCount, fiveDollarCount, twentyDollarCount);if (amount < 0) {throw new IllegalStateException();}this.amount = amount;}public Money substract(Money other) {return new Money(oneCentCount - other.oneCentCount,tenCentCount - other.tenCentCount,quarterCount - other.quarterCount,oneDollarCount - other.oneDollarCount,fiveDollarCount - other.fiveDollarCount,twentyDollarCount - other.twentyDollarCount);}public static Money add(Money money1, Money money2) {return new Money(money1.oneCentCount + money2.oneCentCount,money1.tenCentCount + money2.tenCentCount,money1.quarterCount + money2.quarterCount,money1.oneDollarCount + money2.oneDollarCount,money1.fiveDollarCount + money2.fiveDollarCount,money1.twentyDollarCount + money2.twentyDollarCount);}@Overrideprotected boolean equalsCore(Money other) {return oneCentCount == other.oneCentCount&& tenCentCount == other.tenCentCount&& quarterCount == other.quarterCount&& oneDollarCount == other.oneDollarCount&& fiveDollarCount == other.fiveDollarCount&& twentyDollarCount == other.twentyDollarCount;}@Overrideprotected int getHashCodeCore() {int hashCode = oneCentCount;hashCode = (hashCode * 397) ^ tenCentCount;hashCode = (hashCode * 397) ^ quarterCount;hashCode = (hashCode * 397) ^ oneDollarCount;hashCode = (hashCode * 397) ^ fiveDollarCount;hashCode = (hashCode * 397) ^ twentyDollarCount;return hashCode;}@Overridepublic String toString() {if (getAmount() < 1)return "¢" + getAmount() * 100;return "$" + getAmount();}}
package com.lugew.springbootddd;import org.springframework.data.repository.CrudRepository;/*** @author 夏露桂* @since 2021/6/15 10:50*/public interface SnackMachineRepository extends CrudRepository<SnackMachineDto, Long> {}
const rootURI = "http://localhost:23333/snackmachines/1";getSnackMachine();function getSnackMachine() {$.get(rootURI, function (data, status) {console.log(data)$('#moneyInserted').html(data.moneyInTransaction);$('#cent').html(data.moneyInside.oneCentCount);$('#tenCent').html(data.moneyInside.tenCentCount);$('#quarter').html(data.moneyInside.quarterCount);$('#dollar').html(data.moneyInside.oneDollarCount);$('#fiveDollar').html(data.moneyInside.fiveDollarCount);$('#twentyDollar').html(data.moneyInside.twentyDollarCount);});}$("button").click(function () {switch (this.id) {case "btnInsertCent" :insert("Cent")break;case "btnInsertTenCent" :insert("TenCent")break;case "btnInsertQuarter" :insert("Quarter")break;case "btnInsertDollar" :insert("Dollar")break;case "btnInsertFiveDollar" :insert("FiveDollar")break;case "btnInsertTwentyDollar" :insert("TwentyDollar")break;case "btnReturnMoney" :returnMoney()break;case "btnBuy" :buy("1")break;default :break;}});function insert(coinOrNote) {$.ajax({url: rootURI + '/moneyInTransaction/' + coinOrNote,type: 'PUT',success: function (result) {// Do something with the result}});location.reload();}function returnMoney() {$.ajax({url: rootURI + '/moneyInTransaction',type: 'PUT',success: function (result) {// Do something with the result}});location.reload();}function buy(position) {$.ajax({url: rootURI + '/' + position,type: 'PUT',success: function (result) {}});location.reload();}
再次运行程序就能看到投币、退币和购买功能正常使用:
上述代码有几处缺陷,比如amount转换精度会出现问题,简单起见,这里不做修复,感兴趣的读者可自行重构。
