diff --git a/DesignPattern/DesignPattern.sln b/DesignPattern/DesignPattern.sln
index 93d7f88..512e39d 100644
--- a/DesignPattern/DesignPattern.sln
+++ b/DesignPattern/DesignPattern.sln
@@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Template", "Template\Templa
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "State", "State\State.csproj", "{008D8C56-8546-4EB1-83C6-68FAF2051895}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "State-VendingMachineExample", "State-VendingMachineExample\State-VendingMachineExample.csproj", "{ED14B6E2-04BB-4F77-80E7-C5F0E945B750}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -123,6 +125,10 @@ Global
{008D8C56-8546-4EB1-83C6-68FAF2051895}.Debug|Any CPU.Build.0 = Debug|Any CPU
{008D8C56-8546-4EB1-83C6-68FAF2051895}.Release|Any CPU.ActiveCfg = Release|Any CPU
{008D8C56-8546-4EB1-83C6-68FAF2051895}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ED14B6E2-04BB-4F77-80E7-C5F0E945B750}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ED14B6E2-04BB-4F77-80E7-C5F0E945B750}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ED14B6E2-04BB-4F77-80E7-C5F0E945B750}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ED14B6E2-04BB-4F77-80E7-C5F0E945B750}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/DesignPattern/State-VendingMachineExample/App.config b/DesignPattern/State-VendingMachineExample/App.config
new file mode 100644
index 0000000..aee9adf
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DesignPattern/State-VendingMachineExample/Client.cs b/DesignPattern/State-VendingMachineExample/Client.cs
new file mode 100644
index 0000000..fa56b80
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/Client.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace State_VendingMachineExample
+{
+ internal class Client
+ {
+ public static void HowToTest()
+ {
+ VendingMachine vm = new VendingMachine();
+ vm.AddMoney(1);
+ vm.AddMoney(1);
+ vm.AddMoney(1);
+ vm.AddMoney(1);
+ vm.SelectItem(101);
+ }
+ }
+}
diff --git a/DesignPattern/State-VendingMachineExample/DispenseChangeState.cs b/DesignPattern/State-VendingMachineExample/DispenseChangeState.cs
new file mode 100644
index 0000000..bd7b262
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/DispenseChangeState.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace State_VendingMachineExample
+{
+ internal class DispenseChangeState : VMState
+ {
+ public DispenseChangeState(VendingMachine context)
+ {
+ vendingMachine = context;
+ }
+
+ public override void AddMoney(decimal money)
+ {
+ throw new ApplicationException();
+ }
+
+ public override void ReturnChange(decimal money)
+ {
+ // Return charge here
+ if (vendingMachine.Money > 0)
+ {
+ Console.WriteLine($"Return charge ${money}");
+ vendingMachine.Money -= money;
+ }
+
+ vendingMachine.State = vendingMachine.ReadyState;
+ }
+
+ public override void SelectItem(int itemId)
+ {
+ throw new ApplicationException();
+ }
+ }
+}
diff --git a/DesignPattern/State-VendingMachineExample/DispenseItemState.cs b/DesignPattern/State-VendingMachineExample/DispenseItemState.cs
new file mode 100644
index 0000000..79ce757
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/DispenseItemState.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace State_VendingMachineExample
+{
+ internal class DispenseItemState : VMState
+ {
+ public DispenseItemState(VendingMachine context)
+ {
+ vendingMachine = context;
+ }
+
+ public override void AddMoney(decimal money)
+ {
+ throw new ApplicationException();
+ }
+
+ public override void ReturnChange(decimal money)
+ {
+ throw new ApplicationException();
+ }
+
+ public override void SelectItem(int itemId)
+ {
+ decimal? price = vendingMachine.GetPrice(itemId).Value;
+
+ // Dispense item here
+ Console.WriteLine($"Dispense Item#{itemId} ({price.Value})");
+
+ vendingMachine.Money -= price.Value;
+
+ vendingMachine.State = vendingMachine.DispenseChangeState;
+ vendingMachine.State.ReturnChange(vendingMachine.Money);
+ }
+ }
+}
diff --git a/DesignPattern/State-VendingMachineExample/HasMoneyState.cs b/DesignPattern/State-VendingMachineExample/HasMoneyState.cs
new file mode 100644
index 0000000..63684ca
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/HasMoneyState.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace State_VendingMachineExample
+{
+ 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)
+ {
+ throw new ApplicationException();
+ }
+
+ 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);
+ }
+ }
+}
diff --git a/DesignPattern/State-VendingMachineExample/Product.cs b/DesignPattern/State-VendingMachineExample/Product.cs
new file mode 100644
index 0000000..f7b150f
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/Product.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace State_VendingMachineExample
+{
+ internal class Product
+ {
+ private List- items;
+
+ public Product()
+ {
+ items = new List
- ()
+ {
+ new Item() { Id = 101, Price = 3.50M },
+ new Item() { Id = 201, Price = 4.50M },
+ new Item() { Id = 301, Price = 4.50M }
+ };
+ }
+
+ public decimal? GetPrice(int itemId)
+ {
+ Item item = items.SingleOrDefault(x => x.Id == itemId);
+
+ return item == null ? null : (decimal?)item.Price;
+ }
+
+ private class Item
+ {
+ public int Id { get; set; }
+ public decimal Price { get; set; }
+ }
+ }
+}
diff --git a/DesignPattern/State-VendingMachineExample/Program.cs b/DesignPattern/State-VendingMachineExample/Program.cs
new file mode 100644
index 0000000..2cc6c27
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/Program.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace State_VendingMachineExample
+{
+ internal class Program
+ {
+ static void Main(string[] args)
+ {
+ Client.HowToTest();
+
+ Console.ReadKey();
+ }
+ }
+}
diff --git a/DesignPattern/State-VendingMachineExample/Properties/AssemblyInfo.cs b/DesignPattern/State-VendingMachineExample/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8f62eee
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
+// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
+// 이러한 특성 값을 변경하세요.
+[assembly: AssemblyTitle("State-VendingMachineExample")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("State-VendingMachineExample")]
+[assembly: AssemblyCopyright("Copyright © 2022")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
+// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
+// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
+[assembly: ComVisible(false)]
+
+// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
+[assembly: Guid("ed14b6e2-04bb-4f77-80e7-c5f0e945b750")]
+
+// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
+//
+// 주 버전
+// 부 버전
+// 빌드 번호
+// 수정 버전
+//
+// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
+// 기본값으로 할 수 있습니다.
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/DesignPattern/State-VendingMachineExample/ReadyState.cs b/DesignPattern/State-VendingMachineExample/ReadyState.cs
new file mode 100644
index 0000000..d40e7a1
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/ReadyState.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace State_VendingMachineExample
+{
+ // Concrete State
+ 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 ApplicationException();
+ }
+
+ public override void SelectItem(int itemId)
+ {
+ throw new ApplicationException();
+ }
+ }
+}
diff --git a/DesignPattern/State-VendingMachineExample/State-VendingMachineExample.csproj b/DesignPattern/State-VendingMachineExample/State-VendingMachineExample.csproj
new file mode 100644
index 0000000..2b31148
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/State-VendingMachineExample.csproj
@@ -0,0 +1,61 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {ED14B6E2-04BB-4F77-80E7-C5F0E945B750}
+ Exe
+ State_VendingMachineExample
+ State-VendingMachineExample
+ v4.8.1
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DesignPattern/State-VendingMachineExample/VMState.cs b/DesignPattern/State-VendingMachineExample/VMState.cs
new file mode 100644
index 0000000..4d47328
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/VMState.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace State_VendingMachineExample
+{
+ // State 인터페이스
+ 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);
+ }
+}
diff --git a/DesignPattern/State-VendingMachineExample/VendingMachine.cs b/DesignPattern/State-VendingMachineExample/VendingMachine.cs
new file mode 100644
index 0000000..576e08b
--- /dev/null
+++ b/DesignPattern/State-VendingMachineExample/VendingMachine.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace State_VendingMachineExample
+{
+ // Context
+ internal class VendingMachine
+ {
+ private Product product = new Product();
+ internal decimal Money { get; set; }
+
+ internal VMState State { 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; }
+
+ public VendingMachine()
+ {
+ this.Money = 0;
+ this.ReadyState = new ReadyState(this);
+ this.HasMoneyState = new HasMoneyState(this);
+ this.DispenseItemState = new DispenseItemState(this);
+ this.DispenseChangeState = new DispenseChangeState(this);
+ this.State = this.ReadyState;
+ }
+
+ public void AddMoney(decimal money)
+ {
+ this.State.AddMoney(money);
+ }
+
+ public void SelectItem(int itemId)
+ {
+ this.State.SelectItem(itemId);
+ }
+
+ internal decimal? GetPrice(int itemId)
+ {
+ return product.GetPrice(itemId);
+ }
+ }
+}