HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

Designing another Coffee Machine Application

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
applicationdesigningcoffeeanothermachine

Problem

After reading Designing a coffee machine yesterday, I decided I could also give the same problem a try.

I have used the following problem statement (copied from the given question):


Design a coffee machine which makes different beverages based on set ingredients. The initialization of the recipes for each drink should be hard-coded, although it should be relatively easy to add new drinks. The machine should display the ingredient stock (+cost) and menu upon startup, and after every piece of valid user input. Drink cost is determined by the combination of ingredients. For example, Coffee is 3 units of coffee (75 cents per), 1 unit of sugar (25 cents per), 1 unit of cream (25 cents per). Ingredients and Menu items should be printed in alphabetical order. If the drink is out of stock, it should print accordingly. If the drink is in stock, it should print "Dispensing: ". To select a drink, the user should input a relevant number. If they submit "r" or "R" the ingredients should restock, and "q" or "Q" should quit. Blank lines should be ignored, and invalid input should print an invalid input message.

I may have interpreted some points clearly and a personal remark on the assignment is that the action of restocking is quite abstract and having a single maximum for every ingredient is unrealistic. I still have implemented it that way because "They supplied the default ingredients (&stock @10) and drinks/recipes."

In my decision I have attempted to abstract everything as much as possible, a few points I am aware of:

  • My CoffeeMachineDisplay#processAndContinue method is not really clean, ideally it should be refactored, but I'm unsure how.



  • I have avoided using enums for the ingredients as that limits the applicability of this application in real software, you may want to dynamically load the ingredients and drinks from a database for example.



  • I have kept an eye on obvious performance improvements, though have not wasted too much time and/or code on prematur

Solution

Overall

I like how you made a lot of your classes immutable. I also like the OOP-ness of your code. I'd say you'd definitely "pass the test".

A class just to have a class

public class IngredientSearcher extends Searcher {
    public IngredientSearcher(final Collection ingredients) {
        super(Ingredient::getName, ingredients);
    }
}


I am usually against creating a class just for the sake of creating a class. This can just as well be a static method:

public static Searcher ingredientSearcher(final Collection ingredients) {
    return new Searcher<>(Ingredient::getName, ingredients);
}


The same goes for your DrinkSearcher.

Naming things

DEFAULT_DRINKS is technically not a constant, because it is mutable. I would either name this defaultDrinks, or when creating it, wrap it inside a Collections.unmodifiableList() call.

Pattern IS_DIGIT_PATTERN


Hungarian notation, anyone?

IS_R_PATTERN could be named with what the R means, to make your logic flow more self-documenting. How about IS_REFILL ?

Coffee, Coffee, Coffee, Sugar, Cream

This code is very tedious to write and I bet you used Ctrl + C and Ctrl + V when writing it!

DEFAULT_DRINKS.add(new Drink("Coffee", Arrays.asList(
    ingredientSearcher.search("Coffee"),
    ingredientSearcher.search("Coffee"),
    ingredientSearcher.search("Coffee"),
    ingredientSearcher.search("Sugar"),
    ingredientSearcher.search("Cream")
)));


I think it would be better to add a drink something like this:

.add(Drink.builder("Coffee", ingredientSearcher)
     .with("Coffee", 3)
     .with("Sugar")
     .with("Cream")
     .build()
);

Code Snippets

public class IngredientSearcher extends Searcher<String, Ingredient> {
    public IngredientSearcher(final Collection<? extends Ingredient> ingredients) {
        super(Ingredient::getName, ingredients);
    }
}
public static Searcher<String, Ingredient> ingredientSearcher(final Collection<? extends Ingredient> ingredients) {
    return new Searcher<>(Ingredient::getName, ingredients);
}
Pattern IS_DIGIT_PATTERN
DEFAULT_DRINKS.add(new Drink("Coffee", Arrays.asList(
    ingredientSearcher.search("Coffee"),
    ingredientSearcher.search("Coffee"),
    ingredientSearcher.search("Coffee"),
    ingredientSearcher.search("Sugar"),
    ingredientSearcher.search("Cream")
)));
.add(Drink.builder("Coffee", ingredientSearcher)
     .with("Coffee", 3)
     .with("Sugar")
     .with("Cream")
     .build()
);

Context

StackExchange Code Review Q#83195, answer score: 15

Revisions (0)

No revisions yet.