这个是vending machine的Inventory操作器 可用于currency和货物的操作
package com.company.controller;
import com.company.Model.Currency;
import java.util.*;
public class InventoryController<T> {
private Map<T, Integer> inventoryMap;
public InventoryController() {
inventoryMap = new HashMap<T, Integer>();
}
public int getItemQuantity(T item) {
return inventoryMap.getOrDefault(item, 0);
}
public boolean addItem(T item, int quant) {
inventoryMap.put(item, inventoryMap.getOrDefault(item, 0) + quant);
return true;
}
public boolean deducted(T item, int quant) {
if (getItemQuantity(item) < quant) {
return false;
}
inventoryMap.put(item, inventoryMap.put(item, inventoryMap.get(item)) - quant);
return true;
}
public boolean hasItem(T item) {
return getItemQuantity(item) > 0;
}
public void clear() {
inventoryMap.clear();
}
public void putItem(T item, int quantity) {
inventoryMap.put(item, quantity);
}
public Set<T> getAllItem() {
return inventoryMap.keySet();
}
}
vending machine的接口
import com.company.Model.Currency;
import com.company.Model.Item;
import java.util.Map;
public interface VendingMachine {
public Boolean insertCoin(Currency currency);
public Double getSelectItemPrice(Item item);
public void doRefund(double changes);
public void reset();
public Boolean buy(Item item);
public void ejectInsertedCoins();
public void addIncome();
}
Vending machine的接口实现
package com.company.machines;
import com.company.Model.Currency;
import com.company.Model.Item;
import com.company.controller.InventoryController;
import com.company.exceptions.NotFullPaidException;
import com.company.exceptions.NotSufficientChangeException;
import com.company.exceptions.OutOfStockException;
import java.util.*;
public class VendingMachineImpl implements VendingMachine {
private InventoryController<Currency> currencies;
private InventoryController<Item> items;
private Map<Item, Integer> itemSold;
private static VendingMachineImpl vendingMachine;
private Item selectedItem;
private List<Currency> insertedCurrency;
private VendingMachineImpl() {
currencies = new InventoryController<>();
items = new InventoryController<>();
itemSold = new HashMap<>();
insertedCurrency = new ArrayList<>();
}
@Override
public Boolean insertCoin(Currency currency) {
insertedCurrency.add(currency);
return true;
}
@Override
public Double getSelectItemPrice(Item item) {
if (!items.hasItem(item)) {
throw new OutOfStockException(item.getName());
}
return item.getPrice();
}
@Override
public void doRefund(double changes) {
Map<Currency, Integer> currencyAmount = new HashMap<>();
if (changes == 0.0) {
return;
}
List<Currency> inStockCurrency = new ArrayList<>(currencies.getAllItem());
Collections.sort(inStockCurrency, (a, b) -> Double.compare(b.getValue(), a.getValue()));
for (int i = 0; i < inStockCurrency.size();i++) {
if (changes == 0.0) break;
double val = inStockCurrency.get(i).getValue();
if (val > changes) continue;
int quant = Math.min((int)(changes / val), currencies.getItemQuantity(inStockCurrency.get(i)));
changes -= quant * val;
currencyAmount.put(inStockCurrency.get(i), (int)(quant));
}
if (changes > 0.10) {
throw new NotSufficientChangeException(changes);
}
for (Map.Entry<Currency, Integer> entry: currencyAmount.entrySet()) {
this.currencies.deducted(entry.getKey(), entry.getValue());
}
}
@Override
public void reset() {
currencies.clear();
items.clear();
itemSold.clear();
ejectInsertedCoins();
}
@Override
public Boolean buy(Item item) {
double total = getTotalInsertedValue();
if (item.getPrice() > total) {
throw new NotFullPaidException(item.getPrice(), total);
}
if (!items.hasItem(item)) {
throw new OutOfStockException(item.getName());
}
addIncome();
doRefund(total - item.getPrice());
items.deducted(item, 1);
itemSold.put(item, itemSold.getOrDefault(item, 0) + 1);
return true;
}
@Override
public void ejectInsertedCoins() {
insertedCurrency.clear();
}
@Override
public void addIncome() {
for (Currency inserted: insertedCurrency) {
currencies.addItem(inserted, 1);
}
insertedCurrency.clear();
}
public Map<Item, Integer> getSalesReport() {
return this.itemSold;
}
public Double getTotalInsertedValue() {
Double total = 0.0;
for(Currency currency : insertedCurrency) {
total += currency.getValue();
}
return total;
}
public static VendingMachineImpl getInstance() {
if (vendingMachine == null) {
vendingMachine = new VendingMachineImpl();
vendingMachine.init();
}
return vendingMachine;
}
public void init() {
currencies.addItem(Currency.PENNY, 2);
currencies.addItem(Currency.TEN_DOLLAR_BILL, 1);
currencies.addItem(Currency.DIME, 8);
for(Item item: Item.values()) {
items.addItem(item, 5);
}
}
}
Currency的model
package com.company.Model;
public enum Currency {
PENNY(0.01),
NICKLE(0.05),
DIME(0.1),
QUARTER(0.25),
ONE_DOLLAR_BILL(1.0),
TWO_DOLLAR_BILL(2.0),
FIVE_DOLLAR_BILL(5.0),
TEN_DOLLAR_BILL(10.0),
TWENTY_DOLLAR_BILL(20.0);
private double value;
Currency(double value) {
this.value = value;
}
public double getValue() {
return this.value;
}
}
货物的model
package com.company.Model;
public enum Item {
COKE("Coke", 1.25),
PEPSI("Pepsi", 1.25),
WATER("Water", 1.0);
private String name;
private double price;
private Item(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
没有付全款的异常
package com.company.exceptions;
public class NotFullPaidException extends RuntimeException{
private double expected;
private double actual;
public NotFullPaidException(double expected, double actual) {
this.expected = expected;
this.actual = actual;
}
@Override
public String toString() {
return String.format("expected price: %f:, actual: %f", expected, actual);
}
}
钱箱里的零钱不够的异常
package com.company.exceptions;
public class NotSufficientChangeException extends RuntimeException{
private double need;
public NotSufficientChangeException(double left) {
this.need = left;
}
@Override
public String toString() {
return String.format("Currency stock is not enough, %.2f short", need);
}
}
没货的异常
package com.company.exceptions;
public class OutOfStockException extends RuntimeException {
public String name;
public OutOfStockException(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("%s is out of stock");
}
}