重构代码,结合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
@Setter
public 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")
@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();
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
@Entity
public class SnackMachineDto {
@Id
@GeneratedValue
private 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(new
Money(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
*/
@Getter
public 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, int
oneDollarCount, 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, int
oneDollarCount, 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);
}
@Override
protected boolean equalsCore(Money other) {
return oneCentCount == other.oneCentCount
&& tenCentCount == other.tenCentCount
&& quarterCount == other.quarterCount
&& oneDollarCount == other.oneDollarCount
&& fiveDollarCount == other.fiveDollarCount
&& twentyDollarCount == other.twentyDollarCount;
}
@Override
protected 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;
}
@Override
public 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转换精度会出现问题,简单起见,这里不做修复,感兴趣的读者可自行重构。