I saw this post and tried to do my attempt. This is the requirement of task:
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.
My code looks like this:
CoffeeMachine
public class CoffeeMachine
{
Dictionary<string, ConsoleKey> _productsConsoleKey;
public CoffeeMachine()
{
Initialize();
}
private void Initialize()
{
_productsConsoleKey = new Dictionary<string, ConsoleKey>()
{
{ Products.Mocha, ConsoleKey.D1 },
{ Products.Soy, ConsoleKey.D2 },
{ Products.Whip, ConsoleKey.D3 },
{ Products.DarkRoast, ConsoleKey.D1 },
{ Products.Espresso, ConsoleKey.D2 },
{ Products.HouseBlend, ConsoleKey.D3 },
};
}
public void Start()
{
Beverage beverage;
var beverageFactory = new BeverageFactory();
var stock = new Stock();
var menu = new BeverageMenu(stock, beverageFactory);
while (stock.Count != 0)
{
beverage = SelectCoffee(beverageFactory, stock, menu);
beverage = SelectCondiment(beverage, beverageFactory, stock, menu);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("\n******* Thank you for beverage *******");
Console.WriteLine($"Your beverage is {beverage.Description}. It costs {beverage.Cost()}\n\n\n");
Console.WriteLine("\n******* Thank you for beverage *******");
Console.ForegroundColor = ConsoleColor.Gray;
beverage = null;
}
Console.WriteLine("Sorry, the stock is empty");
}
private Beverage SelectCondiment(Beverage beverage, BeverageFactory beverageFactory, Stock stock, BeverageMenu menu)
{
var emptyProduct = string.Empty;
while (true)
{
menu.Show();
Console.WriteLine();
Console.WriteLine("Please, select a condiment:");
Console.WriteLine($"1. {Products.Mocha} {menu.Items[Products.Mocha]}");
Console.WriteLine($"2. {Products.Soy} {menu.Items[Products.Soy]}");
Console.WriteLine($"3. {Products.Whip} {menu.Items[Products.Whip]}");
Console.WriteLine($"4. No condiment");
var input = Console.ReadKey();
beverage = CreateCondiment(input.Key, ref emptyProduct, beverage, beverageFactory, stock);
if (!string.IsNullOrEmpty(emptyProduct))
Console.WriteLine($"\nPlease, select another condiment as {emptyProduct} is out of stock\n");
else
{
beverage = RestockBeverages(ref emptyProduct, beverage, beverageFactory, stock);
break;
}
}
Console.WriteLine($" \n Your beverage is {beverage.Description} \n ");
return beverage;
}
private Beverage RestockBeverages(ref string emptyProduct, Beverage beverage, BeverageFactory beverageFactory, Stock stock)
{
var restock = true;
while (restock)
{
Console.WriteLine($"\nYour condiment is {beverage.Title}");
Console.WriteLine($"\nPress r to restock {beverage.Title}.\nPress q to quit\n");
var input = Console.ReadKey();
switch (input.Key)
{
case ConsoleKey.R:
beverage = CreateCondiment(_productsConsoleKey[beverage.Title], ref emptyProduct, beverage/**/, beverageFactory, stock);
break;
case ConsoleKey.Q:
restock = false;
break;
}
}
return beverage;
}
private Beverage CreateCondiment(ConsoleKey key, ref string emptyProduct, Beverage beverage, BeverageFactory beverageFactory, Stock stock)
{
switch (key)
{
case ConsoleKey.D1:
case ConsoleKey.NumPad1:
beverage = stock.Items[Products.Mocha] > 0 ? beverageFactory.Mocha(beverage) : null;
emptyProduct = beverage == null ? Products.Mocha : string.Empty;
break;
case ConsoleKey.D2:
case ConsoleKey.NumPad2:
beverage = stock.Items[Products.Soy] > 0 ? beverageFactory.Soy(beverage) : null;
emptyProduct = beverage == null ? Products.Soy : string.Empty;
break;
case ConsoleKey.D3:
case ConsoleKey.NumPad3:
beverage = stock.Items[Products.Whip] > 0 ? beverageFactory.Whip(beverage) : null;
emptyProduct = beverage == null ? Products.Whip : string.Empty;
break;
}
return beverage;
}
private Beverage SelectCoffee(BeverageFactory beverageFactory, Stock stock, BeverageMenu menu)
{
var emptyProduct = string.Empty;
Beverage beverage = beverageFactory.DarkRoast();
while (true)
{
menu.Show();
Console.WriteLine("Please, select a coffee:");
Console.WriteLine($"1. {Products.DarkRoast} {menu.Items[Products.DarkRoast]}");
Console.WriteLine($"2. {Products.Espresso} {menu.Items[Products.Espresso]}");
Console.WriteLine($"3. {Products.HouseBlend} {menu.Items[Products.HouseBlend]}");
var input = Console.ReadKey();
switch (input.Key)
{
case ConsoleKey.D1:
case ConsoleKey.NumPad1:
beverage = stock.Items[Products.DarkRoast] > 0 ? beverageFactory.DarkRoast() : null;
emptyProduct = beverage == null ? Products.DarkRoast : string.Empty;
break;
case ConsoleKey.D2:
case ConsoleKey.NumPad2:
beverage = stock.Items[Products.Espresso] > 0 ? beverageFactory.Espresso() : null;
emptyProduct = beverage == null ? Products.Espresso : string.Empty;
break;
case ConsoleKey.D3:
case ConsoleKey.NumPad3:
beverage = stock.Items[Products.HouseBlend] > 0 ? beverageFactory.HouseBlend() : null;
emptyProduct = beverage == null ? Products.HouseBlend : string.Empty;
break;
}
if (!string.IsNullOrEmpty(emptyProduct))
Console.WriteLine($"\nPlease, select another coffee as {emptyProduct} is out of stock\n");
else
break;
}
Console.WriteLine($" \n Your beverage is {beverage.Description} \n ");
return beverage;
}
}
BeverageMenu
public class BeverageMenu
{
public SortedDictionary<string, string> Items { get; private set; }
private readonly Stock _stock;
private readonly BeverageFactory _beverageFactory;
public BeverageMenu(Stock stock, BeverageFactory beverageFactory)
{
_stock = stock;
_beverageFactory = beverageFactory;
Items = new SortedDictionary<string, string>();
}
public void Show()
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("******* Beverage Menu *******");
Console.ForegroundColor = ConsoleColor.Gray;
if (_stock.Count == 0)
{
Console.WriteLine("Sorry, there is no coffee");
return;
}
if (Items.Count == 0)
{
var houseBlend = _beverageFactory.HouseBlend();
Items.Add(houseBlend.Title, $", Price: {houseBlend.Price}" + HasStock(houseBlend.Title));
var darkRoast = _beverageFactory.DarkRoast();
Items.Add(darkRoast.Title, $", Price: {darkRoast.Price}" + HasStock(darkRoast.Title));
var espresso = _beverageFactory.Espresso();
Items.Add(espresso.Title, $", Price: {espresso.Price}" + HasStock(espresso.Title));
var mocha = _beverageFactory.Mocha(espresso);
Items.Add(mocha.Title, $", Price: {mocha.Price}" + HasStock(mocha.Title));
var whip = _beverageFactory.Whip(espresso);
Items.Add(whip.Title, $", Price: {whip.Price}" + HasStock(whip.Title));
var soy = _beverageFactory.Soy(espresso);
Items.Add(soy.Title, $", Price: {soy.Price}" + HasStock(soy.Title));
}
foreach (var item in Items)
Console.WriteLine(item.Key + item.Value);
}
/// <summary>
/// Whether the stock has product
/// </summary>
/// <param name="productTitle">Title of product</param>
/// <returns></returns>
private string HasStock(string productTitle)
{
return _stock.Items[productTitle] > 0 ? string.Empty : ". Out of the stock";
}
}
Products
public static class Products
{
public static string DarkRoast => "Dark Roast";
public static string Espresso => "Espresso";
public static string HouseBlend => "House Blend Coffee";
public static string Mocha => "Mocha";
public static string Soy => "Soy";
public static string Whip => "Whip";
}
Stock
:
public class Stock
{
public Dictionary<string, int> Items { get; private set; }
/// <summary>
/// Overall Count of items in Stock
/// </summary>
public int Count { get; private set; }
private readonly int INITIAL_COUNT = 10;
public Stock()
{
Initialize();
}
private void Initialize()
{
Items = new Dictionary<string, int>
{
{ Products.DarkRoast, 0 },
{ Products.Espresso, INITIAL_COUNT },
{ Products.HouseBlend, INITIAL_COUNT },
{ Products.Mocha, INITIAL_COUNT },
{ Products.Soy, INITIAL_COUNT },
{ Products.Whip, INITIAL_COUNT }
};
Count = Items.Count * INITIAL_COUNT;
}
public bool GetItem(string productName)
{
if (!Items.ContainsKey(productName))
return false;
if (Items[productName] < 1)
return false;
--Items[productName];
return true;
}
}
Beverage
public abstract class Beverage
{
public abstract string Description { get; }
public abstract double Cost();
public abstract double Price { get; }
public abstract string Title { get; }
}
CondimentDecorator
:
public abstract class CondimentDecorator : Beverage
{
}
DarkRoast
:
public class DarkRoast : Beverage
{
public override string Title => Products.DarkRoast;
public override string Description => Title;
public override double Price => .99;
public override double Cost()
{
return Price;
}
}
Espresso
public class Espresso : Beverage
{
public override string Title => Products.Espresso;
public override string Description => Title;
public override double Price => 1.99;
public override double Cost()
{
return Price;
}
}
HouseBlend
public class HouseBlend : Beverage
{
public override string Title => Products.HouseBlend;
public override string Description => Title;
public override double Price => .89;
public override double Cost()
{
return Price;
}
}
Mocha
:
public class Mocha : CondimentDecorator
{
private readonly Beverage _beverage;
public override string Title => Products.Mocha;
public override string Description => _beverage.Description + $", {Title}";
public override double Price => .20;
public Mocha(Beverage beverage)
{
_beverage = beverage;
}
public override double Cost()
{
return Price + _beverage.Cost();
}
}
Soy
public class Soy : CondimentDecorator
{
private readonly Beverage _beverage;
public override string Title => Products.Soy;
public override string Description => _beverage.Description + $", {Title}";
public override double Price => .15;
public Soy(Beverage beverage)
{
_beverage = beverage;
}
public override double Cost()
{
return Price + _beverage.Cost();
}
}
Whip
public class Whip : CondimentDecorator
{
private readonly Beverage _beverage;
public override double Price => .10;
public override string Title => Products.Whip;
public override string Description => _beverage.Description + $", {Title}";
public Whip(Beverage beverage)
{
_beverage = beverage;
}
public override double Cost()
{
return Price + _beverage.Cost();
}
}
Code can be run though the following code:
static void Main(string[] args)
{
var coffeeMachine = new CoffeeMachine();
coffeeMachine.Start();
}
I am really looking forward to your comments.
Decimal
instead ofdouble
. \$\endgroup\$