Vending machine OOD 根据网上的参考资料自己写的 请大神帮忙看看

这个是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");
    }
}