diff --git a/Program.cs b/Program.cs index b54d3bb..450c50d 100644 --- a/Program.cs +++ b/Program.cs @@ -20,6 +20,7 @@ using design_patterns.behavioral.iterator; using design_patterns.behavioral.mediator; using design_patterns.behavioral.memento; using design_patterns.behavioral.observer; +using design_patterns.behavioral.state; namespace design_patterns { @@ -53,7 +54,8 @@ namespace design_patterns // await IteratorSample.Run(); // await MediatorSample.Run(); // await MementoSample.Run(); - await ObserverSample.Run(); + // await ObserverSample.Run(); + await StateSample.Run(); } catch (System.Exception ex) { diff --git a/behavioral/state/StateSample.cs b/behavioral/state/StateSample.cs new file mode 100644 index 0000000..e2cc03d --- /dev/null +++ b/behavioral/state/StateSample.cs @@ -0,0 +1,128 @@ +using System; +using System.Threading.Tasks; +using Stateless; + +namespace design_patterns.behavioral.state +{ + /// + /// State is a behavioral design pattern that lets an object + /// alter its behavior when its internal state changes. + /// It appears as if the object changed its class. + /// + /// Use it when: + /// - you have an object that behaves differently depending + /// on its current state, the number of states is enormous, + /// and the state-specific code changes frequently. + /// - you have a class polluted with massive conditionals + /// that alter how the class behaves according to the current values + /// of the class’s fields. + /// - you have a lot of duplicate code across similar states + /// and transitions of a condition-based state machine. + /// + /// easy to use STATELESS nuget package + /// https://www.nuget.org/packages/stateless + /// https://github.com/dotnet-state-machine/stateless + /// + public class StateSample + { + public static async Task Run() + { + Console.WriteLine("Behavioral - State"); + + var machineOrder = BuildMachine(); + + var trigger =OrderTrigger.CreateOrder; + machineOrder.Fire(trigger); + System.Console.WriteLine($"state: {machineOrder.State}"); + if(machineOrder.State != OrderState.New) + System.Console.WriteLine($"Error with order state trigger {trigger} - state {machineOrder.State}"); + + trigger =OrderTrigger.RegisterOrder; + machineOrder.Fire(trigger); + System.Console.WriteLine($"state: {machineOrder.State}"); + if(machineOrder.State != OrderState.Registered) + System.Console.WriteLine($"Error with order state trigger {trigger} - state {machineOrder.State}"); + + + // // once cancelled it cannot migrate to other sates + // trigger = OrderTrigger.CancellByCustomer; + // machineOrder.Fire(trigger); + // System.Console.WriteLine($"state: {machineOrder.State}"); + + trigger = OrderTrigger.BeginProcessing; + machineOrder.Fire(trigger); + System.Console.WriteLine($"state: {machineOrder.State}"); + + trigger = OrderTrigger.Packaging; + machineOrder.Fire(trigger); + System.Console.WriteLine($"state: {machineOrder.State}"); + + trigger = OrderTrigger.Shipping; + machineOrder.Fire(trigger); + System.Console.WriteLine($"state: {machineOrder.State}"); + + trigger = OrderTrigger.Delivering; // or .ReturnByCustomer or .ReturnByShipment + machineOrder.Fire(trigger); + System.Console.WriteLine($"state: {machineOrder.State}"); + } + + public static StateMachine BuildMachine() { + var machineOrder = new StateMachine(OrderState.New); + // from new to draft + machineOrder.Configure(OrderState.New) + .PermitReentry(OrderTrigger.CreateOrder) + .Permit(OrderTrigger.SaveAsDraft, OrderState.Draft) + .Permit(OrderTrigger.RegisterOrder, OrderState.Registered); + + // from draft to registered + machineOrder.Configure(OrderState.Draft) + .Permit(OrderTrigger.RegisterOrder, OrderState.Registered); + // from registered to cancelled or begin processing + machineOrder.Configure(OrderState.Registered) + .Permit(OrderTrigger.CancellByCustomer, OrderState.Cancelled) + .Permit(OrderTrigger.BeginProcessing, OrderState.Processing); + // from processing to cancelled of packaging + machineOrder.Configure(OrderState.Processing) + .Permit(OrderTrigger.CancellBySupplier, OrderState.Cancelled) + .Permit(OrderTrigger.Packaging, OrderState.Packaged); + // from packaged to shipped or return + machineOrder.Configure(OrderState.Packaged) + .Permit(OrderTrigger.Shipping, OrderState.Shipped) + .Permit(OrderTrigger.ReturnByShipment, OrderState.ReturnedByShipment); + // from shipped to + machineOrder.Configure(OrderState.Shipped) + .Permit(OrderTrigger.Delivering, OrderState.Completed) + .Permit(OrderTrigger.ReturnByShipment, OrderState.ReturnedByShipment) + .Permit(OrderTrigger.ReturnByCustomer, OrderState.ReturnedByCustomer); + return machineOrder; + } + + public enum OrderState { + New, + Draft, + Registered, + Processing, + Packaged, + Shipped, + Completed, + // other states + Cancelled, + ReturnedByShipment, + ReturnedByCustomer + } + + public enum OrderTrigger { + CreateOrder, + SaveAsDraft, + RegisterOrder, + CancellByCustomer, + CancellBySupplier, + BeginProcessing, + Packaging, + Shipping, + Delivering, + ReturnByShipment, + ReturnByCustomer + } + } +} \ No newline at end of file diff --git a/design_patterns.csproj b/design_patterns.csproj index 1d2d39a..91f04cb 100644 --- a/design_patterns.csproj +++ b/design_patterns.csproj @@ -5,4 +5,8 @@ net5.0 + + + +