Простое приложение бариста для расчета цены на напиток на основе различных ингредиентов


Сценарий заключается в том, что клиент заказывает кофе из автомата, выбрав выбор из нескольких категорий, такие, как размер, вкус, а сливки типа.

Учитывая их выбор, то мы должны выяснить стоимость.

Поворот в том, что различные варианты сливочник стоить немного больше, если вы получаете очень большой кофе.

Например, если вы выберете молока как ваш сливочник, это обычно 50 копеек; но, если вы выберете XL, как ваши размер, молоко стоит 60 центов.

public enum Coffee {

    CAFFEE_AMERICANO("Coffee", .75),
    CAFFEE_LATTE("Caffee Latte" , .50),
    CAFFE_MOCHA("Caffee Mocha" , .65),
    CAPPUCCINO("Cappuccino" , .85),
    COFFEE("Caffee" , .95),
    DECAF_COFFEE("Decaf Coffee" , .45);

    private final String name;
    private final double unit_price;

    private Coffee(String name, double unit_cost)
    {
        this.name = name;
        this.unit_price = unit_cost;
    }

    public String getName() {
        return name;
    }

    public double getUnit_price() {
        return unit_price;
    }

}

public enum Creamer {

    NONE("None", 0.0),
    MILK("Milk", 0.50),
    HALF_N_HALF("Half and Half", 0.25),

    TALL_MILK("Milk", 0.60),
    TALL_HALF_N_HALF("Half and Half", 0.35),

    GRANDE_MILK("Grande Milk", 0.65),
    GRANDE_HALF_N_HALF("Grande Half and Half", 0.45),

    VENTI_MILK("Venti Milk", 0.70),
    VENTI_HALF_N_HALF("Venti Half and Half", 0.55),

    TRENTA_MILK("Trenta Milk", 0.75),
    TRENTA_HALF_N_HALF("Trenta Half and Half", 0.60);


    private String name;
    private double price;

    private Creamer(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;
    }

}

public class PricingEngine {

    public static double priceBasedOnSize(Map<String, Enum> ingredients) {

        double totalCost = 0.0;
        Coffee coffee = (Coffee) ingredients.get("Coffee");
        totalCost += coffee.getUnit_price();

        Size size = (Size) ingredients.get("Size");

        Creamer creamer = (Creamer) ingredients.get("Creamer");

        // get price based on the creamer and cup size

        String priceBySize = size.name() + "_" + creamer.name();

        totalCost += Creamer.valueOf(priceBySize).getPrice();

        return totalCost;

    }

}

public enum Size {

    TALL("Tall"),
    GRANDE("Grande"),
    VENTI("Venti"),
    TRENTA("Trenta");

    private String name;

    private Size(String name)
    {
        this.name= name;
    }

    public String getName()
    {
        return this.name();
    }

}

public class BaristaMain {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        boolean appRunning = true;
        Map<String, Enum> map = new HashMap<String, Enum>();
        System.out.println("Welcome to automatic coffee dispensing service\n\n");
        while (appRunning) {

            System.out.print("1. Caffe Americano");
            System.out.print(" 2. Caffe Latte");
            System.out.print(" 3. Caffe Mocha");
            System.out.print(" 4. Cappuccino");
            System.out.print(" 5. Coffee");
            System.out.println(" 6. Decaf Coffee");
            System.out.println("Please enter your choice: ");
            int chioiceOfCoffee = in.nextInt();

            if (chioiceOfCoffee == 1) {
                map.put("Coffee", Coffee.CAFFEE_AMERICANO);

            } else if (chioiceOfCoffee == 2) {
                map.put("Coffee", Coffee.CAFFEE_LATTE);

            } else if (chioiceOfCoffee == 3) {
                map.put("Coffee", Coffee.CAFFE_MOCHA);

            } else if (chioiceOfCoffee == 4) {
                map.put("Coffee", Coffee.CAPPUCCINO);

            } else if (chioiceOfCoffee == 5) {
                map.put("Coffee", Coffee.COFFEE);

            } else if (chioiceOfCoffee == 6) {
                map.put("Coffee", Coffee.DECAF_COFFEE);

            } else {
                System.out.println("Your entry: " + chioiceOfCoffee + " is not valide. Please enter a valid choice.");
            }

            System.out.print("1. Tall(Slept 8-10 Hours)");
            System.out.print(" 2. Grande(Slept 5-7 Hours)");
            System.out.print(" 3. Venti(Slept 0-4 Hours");
            System.out.println(" 4. Trenta(WTF is sleep?)");
            System.out.println("Please enter your cup size: ");
            int cupSize = in.nextInt();

            if (cupSize == 1) {
                map.put("Size", Size.TALL);

            } else if (cupSize == 2) {
                map.put("Size", Size.GRANDE);

            } else if (cupSize == 3) {
                map.put("Size", Size.VENTI);

            } else if (cupSize == 4) {
                map.put("Size", Size.TRENTA);

            } else {
                System.out.println(
                    "Your entry for cup size : " + cupSize + " is not valide. Please enter a valid choice.");
            }

            System.out.print("1. NONE");
            System.out.print(" 2. MILK");
            System.out.println(" 3. HALF_N_HALF");
            System.out.println("Please enter your choice of creamer: ");
            int creamer = in.nextInt();

            if (creamer == 1) {
                map.put("Creamer", Creamer.NONE);

            } else if (creamer == 2) {
                map.put("Creamer", Creamer.MILK);

            } else if (creamer == 3) {
                map.put("Creamer", Creamer.HALF_N_HALF);

            } else {
                System.out.println(
                    "Your entry for cup size : " + cupSize + " is not valide. Please enter a valid choice.");
            }

            System.out.println();

            System.out.println("Dispensing.............");

            System.out.println("Total Cost: " + PricingEngine.priceBasedOnSize(map));
            System.out.println("Enjoy your coffee!");

        }

    }

}

Я знаю, что есть 5 другими способами (например, шаблон "декоратор"), но по некоторым причинам решение должен иметь перечислимый.

Дайте мне знать, что вы думаете об этом решении. Любое улучшение на механизм ценообразования будет полезно.

Там могут быть другие категории, а также, что может измениться цена на кофе.



282
1
задан 4 февраля 2018 в 08:02 Источник Поделиться
Комментарии
2 ответа

Общие Реализации

Я бы склонялся в сторону интерфейса Priceable, что лишние перечисления реализовать, и кофе хранение списка дополнительных услуг, которые могут быть переданы размера и возвращают значение, чтобы добавить к цене.

enum Creamer implements Priceable {
NONE {
@Override
public double getPrice(Size size) {
return 0;
}
}, MILK {
@Override
public double getPrice(Size size) {
switch (size) {
case TALL:
return 0.6;
case GRANDE:
return 0.65;
case VENTI:
return 0.70;
case TRENTA:
return 0.75;
default:
throw new AssertionError("Unknown size");
}
}
}, HALF_N_HALF {
@Override
public double getPrice(Size size) {
switch (size) {
case TALL:
return 0.35;
case GRANDE:
return 0.45;
case VENTI:
return 0.50;
case TRENTA:
return 0.6;
default:
throw new AssertionError("Unknown size");
}
}
};
}

interface Priceable {
public double getPrice(Size size);
}

Использование двойной для денег

Я бы попробовал использовать int вместо Double, если это возможно, так что вам не придется иметь дело с плавающими вопросы точку.

Проверка ввода

На данный момент исключение, если пользователь делает плохого, вы, вероятно, хотите вместо того, чтобы справиться с этим.

Используя порядковые числительные

С помощью values() массив можно избежать переключения на перечисление членов, чтобы получить их по индексу.

4
ответ дан 4 февраля 2018 в 09:02 Источник Поделиться

Спасибо за ваш код.

Мне нравится enum подход, но он может быть улучшен.

Моя проблема с ваш подход заключается в том, что вы регулируете размер пить как ингредиент.

С другой стороны вы отделяете "ХЛ" цена сливки от сливок, где он может быть собственностью сливочник.

Так что я бы создать общий интерфейс для всех типов кофе и сливки, так что я могу держать их в тот же список:

interface Ingredient{
/** @return the ingredient price depending on the drinks size +/
double getPrice(Size size);
}

Сливочник enum реализует этот интерфейс:

enum Creamer implements Ingredient {
NONE("None"){
@override
public double getPrice(Size size){
return 0.0; // same value for all
}
},
MILK("Milk", 0.50, 0.65, 0.70, 0.75),
HALF_N_HALF("Half and Half", 0.25, 0.45, 0.55, 0.60);

private final double[] prices;
private final String name;
Creamer(String name, double ... prices){
this.name = name;
this.prices = prices;
}
@override
public double getPrice(Size size){
return prices[size.ordinal()]; // enum Size should have a dedicated getIndex() method to be independent from order in the enum.
}
public String getName() {
return name;
}
}

Мой тип используемого кофе тип также будет реализовывать этот интерфейс, так как это не проблема для разработчика, чтобы игнорировать параметр размера. Также это позволяет легко вводить зависит размер цены на кофе тоже, но это побочный эффект, не предназначенные:

enum Coffe implements Ingredient {

CAFFEE_AMERICANO("Coffee", .75),
CAFFEE_LATTE("Caffee Latte" , .50),
CAFFE_MOCHA("Caffee Mocha" , .65),
CAPPUCCINO("Cappuccino" , .85),
COFFEE("Caffee" , .95),
DECAF_COFFEE("Decaf Coffee" , .45);

private final String name;
private final double unitPrice;

private Coffee(String name, double unitCost)
{
this.name = name;
this.unitPrice = unitCost;
}

public String getName() {
return name;
}

@override
public double gePrice(Size size) {
return unitPrice;
}
}

Имея это, я могу собрать кофе и сливки в Collection<Ingredient> (а не в Map) и передать этот список вместе с выбранным размерам PricingEngine:

public class PricingEngine {

public static double priceBasedOnSize(Collection<Ingredient> ingredients, Size size) {
double totalCost = 0.0;
for(Ingredient ingredient : ingredients)
totalCost += ingredient.getPrice(size);
return totalCost;
// alternative with Java8
return ingredients.stram().
.mapToDouble(ingredient.getPrice(size))
.sum();
}

}

Преимущества:


  • никакой разницы между кофе и сливками.

  • короче

  • поддерживает несколько типов ингредиент (например, дополнительный "вкус") без изменений. Но опять же: это побочный эффект, не предназначены.

2
ответ дан 4 февраля 2018 в 10:02 Источник Поделиться