From ebf7cddb25ff45284eac44ea5103a45d82bf17c9 Mon Sep 17 00:00:00 2001 From: syneffort Date: Thu, 29 Feb 2024 16:03:25 +0900 Subject: [PATCH] state machine --- .../DesignPattern/Patterns/StateMachine.cs | 236 ++++++++++++++++++ DesignPattern/DesignPattern/Program.cs | 4 +- 2 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 DesignPattern/DesignPattern/Patterns/StateMachine.cs diff --git a/DesignPattern/DesignPattern/Patterns/StateMachine.cs b/DesignPattern/DesignPattern/Patterns/StateMachine.cs new file mode 100644 index 0000000..d0e7536 --- /dev/null +++ b/DesignPattern/DesignPattern/Patterns/StateMachine.cs @@ -0,0 +1,236 @@ +namespace DesignPattern.Patterns +{ + public class StateMachinePattern + { + public static void Work() + { + VendingMachine vendingMachine = new VendingMachine(); + + while (true) + { + Console.WriteLine("Please select action (AddMoney, SelectItem, ReturnChange)"); + string input = Console.ReadLine(); + string read; + switch (input.ToUpper()) + { + case "ADDMONEY": + Console.Write("Money: "); + read = Console.ReadLine(); + int.TryParse(read, out int money); + vendingMachine.AddMoney(money); + break; + case "SELECTITEM": + Console.Write("ItemId: "); + read = Console.ReadLine(); + int.TryParse(read, out int itemId); + vendingMachine.SelectItem(itemId); + break; + case "RETURNCHANGE": + vendingMachine.ReturnChange(); + break; + } + } + } + } + + public class VendingMachine + { + private Product product = new Product(); + internal decimal Money { get; set; } + + internal VMState ReadyState { get; private set; } + internal VMState HasMoneyState { get; private set; } + internal VMState DispenseItemState { get; private set; } + internal VMState DispenseChangeState { get; private set; } + internal VMState State { get; set; } + + public VendingMachine() + { + Money = 0; + + ReadyState = new ReadyState(this); + HasMoneyState = new HasMoneyState(this); + DispenseItemState = new DispenseItemState(this); + DispenseChangeState = new DispenseChangeState(this); + + State = ReadyState; + } + + public void AddMoney(decimal money) + { + State.AddMoney(money); + } + + public void SelectItem(int itemId) + { + State.SelectItem(itemId); + } + + public void ReturnChange() + { + State.ReturnChange(Money); + } + + internal decimal? GetPrice(int itemId) + { + return product.GetPrice(itemId); + } + } + + internal class Product + { + private List _items; + + public Product() + { + _items = new List() + { + new Item() { Id = 101, Price = 3.5M }, + new Item() { Id = 201, Price = 4.0M }, + new Item() { Id = 301, Price = 4.5M }, + }; + } + + public decimal? GetPrice(int itemid) + { + var item = _items.SingleOrDefault(p => p.Id == itemid); + + return item == null ? null : (decimal?)item.Price; + } + + private class Item + { + public int Id { get; set; } + public decimal Price { get; set; } + } + } + + internal abstract class VMState + { + protected VendingMachine _vendingMachine; + public abstract void AddMoney(decimal money); + public abstract void SelectItem(int itemId); + public abstract void ReturnChange(decimal money); + } + + internal class ReadyState : VMState + { + public ReadyState(VendingMachine context) + { + _vendingMachine = context; + } + + public override void AddMoney(decimal money) + { + _vendingMachine.State = _vendingMachine.HasMoneyState; + _vendingMachine.State.AddMoney(money); + } + + public override void ReturnChange(decimal money) + { + throw new InvalidOperationException(); + } + + public override void SelectItem(int itemId) + { + throw new InvalidOperationException(); + } + } + + internal class HasMoneyState : VMState + { + public HasMoneyState(VendingMachine context) + { + _vendingMachine = context; + } + + public override void AddMoney(decimal money) + { + _vendingMachine.Money += money; + Console.WriteLine($"Add {money}, Balance: {_vendingMachine.Money}"); + } + + public override void ReturnChange(decimal money) + { + _vendingMachine.State = _vendingMachine.DispenseChangeState; + _vendingMachine.State.ReturnChange(_vendingMachine.Money); + } + + public override void SelectItem(int itemId) + { + decimal? price = _vendingMachine.GetPrice(itemId).Value; + if (!price.HasValue) + { + Console.WriteLine($"{itemId} not found"); + return; + } + + if (_vendingMachine.Money < price.Value) + { + Console.WriteLine("Insufficient money"); + return; + } + + _vendingMachine.State = _vendingMachine.DispenseItemState; + _vendingMachine.State.SelectItem(itemId); + } + } + + internal class DispenseItemState : VMState + { + public DispenseItemState(VendingMachine context) + { + _vendingMachine = context; + } + + public override void AddMoney(decimal money) + { + throw new InvalidOperationException(); + } + + public override void ReturnChange(decimal money) + { + throw new InvalidOperationException(); + } + + public override void SelectItem(int itemId) + { + decimal? price = _vendingMachine.GetPrice(itemId).Value; + + Console.WriteLine($"Dispense item#{itemId} ({price.Value})"); + _vendingMachine.Money -= price.Value; + + _vendingMachine.State = _vendingMachine.DispenseChangeState; + _vendingMachine.State.ReturnChange(_vendingMachine.Money); + } + } + + internal class DispenseChangeState : VMState + { + public DispenseChangeState(VendingMachine context) + { + _vendingMachine = context; + } + + public override void AddMoney(decimal money) + { + throw new InvalidOperationException(); + } + + public override void ReturnChange(decimal money) + { + if (_vendingMachine.Money > 0) + { + Console.WriteLine($"Return change {money}..."); + _vendingMachine.Money -= money; + } + + _vendingMachine.State = _vendingMachine.ReadyState; + } + + public override void SelectItem(int itemId) + { + throw new InvalidOperationException(); + } + } +} \ No newline at end of file diff --git a/DesignPattern/DesignPattern/Program.cs b/DesignPattern/DesignPattern/Program.cs index 3ae68b7..5952599 100644 --- a/DesignPattern/DesignPattern/Program.cs +++ b/DesignPattern/DesignPattern/Program.cs @@ -8,6 +8,8 @@ class Program { // FactoryClient.Work(); - CommandClient.Work(); + // CommandClient.Work(); + + StateMachinePattern.Work(); } }