Add command pattern
This commit is contained in:
@@ -14,6 +14,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BehavioralPatterns", "src\B
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ChainOfResponssibility", "src\ChainOfResponssibility\ChainOfResponssibility.xproj", "{89536824-683F-4351-8789-406D7BDD922D}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CommandPattern", "src\CommandPattern\CommandPattern.xproj", "{454B2A43-8251-4667-8DE3-67E489908DB9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -28,6 +30,10 @@ Global
|
||||
{89536824-683F-4351-8789-406D7BDD922D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{89536824-683F-4351-8789-406D7BDD922D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{89536824-683F-4351-8789-406D7BDD922D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{454B2A43-8251-4667-8DE3-67E489908DB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{454B2A43-8251-4667-8DE3-67E489908DB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{454B2A43-8251-4667-8DE3-67E489908DB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{454B2A43-8251-4667-8DE3-67E489908DB9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -35,5 +41,6 @@ Global
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{E3092EE0-1282-4AB4-9FA2-0338348D8FD1} = {3820200F-354C-41E6-8F34-B301F5D621C2}
|
||||
{89536824-683F-4351-8789-406D7BDD922D} = {3820200F-354C-41E6-8F34-B301F5D621C2}
|
||||
{454B2A43-8251-4667-8DE3-67E489908DB9} = {3820200F-354C-41E6-8F34-B301F5D621C2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using ChainOfResponssibility;
|
||||
using ChainOfResponssibility.PurchaseExample;
|
||||
using CommandPattern;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -16,6 +17,8 @@ namespace BehavioralPatterns
|
||||
//This is usefull when you have a request and you don't know who should process it
|
||||
ChainOfResponsibillityExamples.Run();
|
||||
Console.ReadKey();
|
||||
CommandPatternExamples.Run();
|
||||
Console.ReadKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
"dependencies": {
|
||||
"ChainOfResponssibility": "1.0.0-*",
|
||||
"CommandPattern": "1.0.0-*",
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0-rc2-3002702"
|
||||
|
||||
21
src/CommandPattern/CommandPattern.xproj
Normal file
21
src/CommandPattern/CommandPattern.xproj
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>454b2a43-8251-4667-8de3-67e489908db9</ProjectGuid>
|
||||
<RootNamespace>CommandPattern</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
45
src/CommandPattern/CommandPatternExamples.cs
Normal file
45
src/CommandPattern/CommandPatternExamples.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using CommandPattern.StocksExample;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommandPattern
|
||||
{
|
||||
public class CommandPatternExamples
|
||||
{
|
||||
public static void Run()
|
||||
{
|
||||
Console.WriteLine(GetPatternDescription());
|
||||
GoToNextStep();
|
||||
|
||||
StockExampleRunner stockExampleRunner = new StockExampleRunner();
|
||||
Console.WriteLine(stockExampleRunner.GetDescriptionOfExample());
|
||||
GoToNextStep();
|
||||
stockExampleRunner.Run();
|
||||
stockExampleRunner.Run();
|
||||
stockExampleRunner.Run();
|
||||
stockExampleRunner.Run();
|
||||
}
|
||||
|
||||
private static void GoToNextStep()
|
||||
{
|
||||
Console.ReadKey();
|
||||
Console.Clear();
|
||||
}
|
||||
|
||||
public static string GetPatternDescription()
|
||||
{
|
||||
return @"
|
||||
command pattern is a behavioral design pattern in which an object is used to encapsulate
|
||||
all information needed to perform an action or trigger an event at a later time
|
||||
Uses:
|
||||
1. Macro recording: f all user actions are represented by command objects, a program can record a
|
||||
sequence of actions simply by keeping a list of the command objects as they are executed.
|
||||
2. Undo
|
||||
3. GUI buttons and menu items
|
||||
4. Parallel processing
|
||||
5. Transactional behavior ";
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/CommandPattern/Program.cs
Normal file
14
src/CommandPattern/Program.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommandPattern
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/CommandPattern/Properties/AssemblyInfo.cs
Normal file
19
src/CommandPattern/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Hewlett-Packard Company")]
|
||||
[assembly: AssemblyProduct("CommandPattern")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("454b2a43-8251-4667-8de3-67e489908db9")]
|
||||
47
src/CommandPattern/StocksExample/Agent.cs
Normal file
47
src/CommandPattern/StocksExample/Agent.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommandPattern.StocksExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoker. The invoker will invoke the command
|
||||
/// </summary>
|
||||
public class Agent
|
||||
{
|
||||
Stack<Order> ordersNotExecuted;
|
||||
FixedSizedQueue<Order> ordersPlaced;
|
||||
StockSchedule stockSchedule;
|
||||
|
||||
public Agent(StockSchedule stockSchedule)
|
||||
{
|
||||
ordersNotExecuted = new Stack<Order>();
|
||||
ordersPlaced = new FixedSizedQueue<Order>(10);
|
||||
this.stockSchedule = stockSchedule;
|
||||
stockSchedule.StockExchangedOpened += StockSchedule_StockExchangedOpened;
|
||||
}
|
||||
|
||||
private void StockSchedule_StockExchangedOpened(object sender, EventArgs e)
|
||||
{
|
||||
while (ordersNotExecuted.Any())
|
||||
{
|
||||
PlaceOrder(ordersNotExecuted.Pop());
|
||||
}
|
||||
}
|
||||
|
||||
public void PlaceOrder(Order order)
|
||||
{
|
||||
if(stockSchedule.IsStockOpen())
|
||||
{
|
||||
order.Execute();
|
||||
ordersPlaced.Enqueue(order);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Market is not opened, so the order was saved for later");
|
||||
ordersNotExecuted.Push(order);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/CommandPattern/StocksExample/Commands/BuyStockOrder.cs
Normal file
24
src/CommandPattern/StocksExample/Commands/BuyStockOrder.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommandPattern.StocksExample.Commands
|
||||
{
|
||||
//Concrete Command
|
||||
public class BuyStockOrder : Order
|
||||
{
|
||||
StocksAPI stocksAPI;
|
||||
Stock stock;
|
||||
public BuyStockOrder(StocksAPI stocksAPI, Stock stock)
|
||||
{
|
||||
this.stocksAPI = stocksAPI;
|
||||
this.stock = stock;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
stocksAPI.Buy(stock);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/CommandPattern/StocksExample/Commands/SellStockOrder.cs
Normal file
23
src/CommandPattern/StocksExample/Commands/SellStockOrder.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommandPattern.StocksExample.Commands
|
||||
{
|
||||
public class SellStockOrder : Order
|
||||
{
|
||||
StocksAPI stocksAPI;
|
||||
Stock stock;
|
||||
public SellStockOrder(StocksAPI stocksAPI, Stock stock)
|
||||
{
|
||||
this.stocksAPI = stocksAPI;
|
||||
this.stock = stock;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
stocksAPI.Sell(stock);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/CommandPattern/StocksExample/FixedSizedQueue.cs
Normal file
29
src/CommandPattern/StocksExample/FixedSizedQueue.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace CommandPattern.StocksExample
|
||||
{
|
||||
public class FixedSizedQueue<T> : ConcurrentQueue<T>
|
||||
{
|
||||
private readonly object syncObject = new object();
|
||||
|
||||
public int Size { get; private set; }
|
||||
|
||||
public FixedSizedQueue(int size)
|
||||
{
|
||||
Size = size;
|
||||
}
|
||||
|
||||
public new void Enqueue(T obj)
|
||||
{
|
||||
base.Enqueue(obj);
|
||||
lock (syncObject)
|
||||
{
|
||||
while (Count > Size)
|
||||
{
|
||||
T outObj;
|
||||
TryDequeue(out outObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/CommandPattern/StocksExample/Order.cs
Normal file
15
src/CommandPattern/StocksExample/Order.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommandPattern.StocksExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Command interface
|
||||
/// </summary>
|
||||
public interface Order
|
||||
{
|
||||
void Execute();
|
||||
}
|
||||
}
|
||||
8
src/CommandPattern/StocksExample/Stock.cs
Normal file
8
src/CommandPattern/StocksExample/Stock.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace CommandPattern.StocksExample
|
||||
{
|
||||
public class Stock
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
}
|
||||
}
|
||||
30
src/CommandPattern/StocksExample/StockExampleRunner.cs
Normal file
30
src/CommandPattern/StocksExample/StockExampleRunner.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using CommandPattern.StocksExample.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommandPattern.StocksExample
|
||||
{
|
||||
public class StockExampleRunner
|
||||
{
|
||||
public void Run()
|
||||
{
|
||||
StocksAPI stocksAPI = new StocksAPI();
|
||||
Agent agent = new Agent(new StockSchedule());
|
||||
|
||||
Stock stock = new Stock { Name = "AAPL", Quantity = 20 };
|
||||
|
||||
agent.PlaceOrder(new BuyStockOrder(stocksAPI, stock));
|
||||
agent.PlaceOrder(new SellStockOrder(stocksAPI, stock));
|
||||
}
|
||||
|
||||
public string GetDescriptionOfExample()
|
||||
{
|
||||
return @"
|
||||
Buy or sell a stock on the market.
|
||||
If the market is closed save the orders for when the market opens again.
|
||||
When the market opens place all the orders.";
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/CommandPattern/StocksExample/StockSchedule.cs
Normal file
50
src/CommandPattern/StocksExample/StockSchedule.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace CommandPattern.StocksExample
|
||||
{
|
||||
public class StockSchedule
|
||||
{
|
||||
TimeSpan openingTime;
|
||||
public StockSchedule()
|
||||
{
|
||||
CheckForOpeningOfStockExchange();
|
||||
openingTime = new TimeSpan(9, 0, 0);
|
||||
}
|
||||
|
||||
public event EventHandler StockExchangedOpened;
|
||||
|
||||
public bool IsStockOpen()
|
||||
{
|
||||
return new Random().NextDouble() > 0.5;
|
||||
}
|
||||
|
||||
private void OnStockExchangedOpened(object state)
|
||||
{
|
||||
StockExchangedOpened?.Invoke(this, null);
|
||||
Thread.Sleep(1);
|
||||
CheckForOpeningOfStockExchange();
|
||||
|
||||
}
|
||||
|
||||
private void CheckForOpeningOfStockExchange()
|
||||
{
|
||||
var t = new Timer(new TimerCallback(OnStockExchangedOpened), null, Timeout.Infinite, Timeout.Infinite);
|
||||
|
||||
// Figure how much time until opening market
|
||||
DateTime now = DateTime.Now;
|
||||
DateTime openingTime = DateTime.Today.Add(this.openingTime);
|
||||
|
||||
// If it's already past opening time, wait until opening time tomorrow
|
||||
if (now > openingTime)
|
||||
{
|
||||
openingTime = openingTime.AddDays(1.0);
|
||||
}
|
||||
|
||||
int msUntilOpeningHour = (int)((openingTime - now).TotalMilliseconds);
|
||||
|
||||
// Set the timer to elapse only once, at opening time.
|
||||
t.Change(msUntilOpeningHour, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/CommandPattern/StocksExample/StocksAPI.cs
Normal file
20
src/CommandPattern/StocksExample/StocksAPI.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace CommandPattern.StocksExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Receiver of the command. Concrete command is executing code from this class
|
||||
/// </summary>
|
||||
public class StocksAPI
|
||||
{
|
||||
public void Buy(Stock stock)
|
||||
{
|
||||
Console.WriteLine("Stock [ Name: {0}, Quantity: {1} bought", stock.Name, stock.Quantity);
|
||||
}
|
||||
|
||||
public void Sell(Stock stock)
|
||||
{
|
||||
Console.WriteLine("Stock [ Name: {0}, Quantity: {1} sold", stock.Name, stock.Quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/CommandPattern/project.json
Normal file
19
src/CommandPattern/project.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "1.0.0-*",
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0-rc2-3002702"
|
||||
}
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": "dnxcore50"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user