Objective ๐ฏ
Allow an object alter its own behavior when its state changes.
Type โ
โ๏ธBehavioral: Describes how objects interact/communicate between themselves.
โCreational: Describes how to instantiate an object without large and complex.
โStructural: Describes how objects/classes are composed to form larger structures.
UML ๐
Participants ๐
โข Context:
- Represents the class that will be used by the Client
- Maintains an instance of a ConcreteState class that represents the current state
โข State:
- Defines an interface for encapsulating the behavior associated with a particular state of the Context.
โข Concrete State:
- Represents a specific behavior for a particular Context
Sample Code ๐ฎ
Structural Example ๐๏ธ
public static class StateStructural
{
public static void Execute()
{
Context lContext = new Context(new ConcreteStateA());
lContext.Request(); // State A > State B
lContext.Request(); // State B > State C
lContext.Request(); // State C > State A
}
}
public abstract class State
{
public abstract void Handle(Context prContext);
}
public class ConcreteStateA : State
{
public override void Handle(Context prContext)
{
Console.WriteLine("Concrete State A - Executing method \"Handle\" and changing state to \"B\"");
prContext._State = new ConcreteStateB();
}
}
public class ConcreteStateB : State
{
public override void Handle(Context prContext)
{
Console.WriteLine("Concrete State B - Executing method \"Handle\" and changing state to \"C\"");
prContext._State = new ConcreteStateC();
}
}
public class ConcreteStateC : State
{
public override void Handle(Context prContext)
{
Console.WriteLine("Concrete State C - Executing method \"Handle\" and changing state back to \"A\"");
prContext._State = new ConcreteStateA();
}
}
public class Context
{
public State _State;
public Context(State prState)
{
_State = prState;
}
public void Request()
{
_State.Handle(this);
}
}
Output
Real-world Example ๐ฅ
public static class StatePractical
{
public static void Execute()
{
DocumentContext lDocumentContext = new DocumentContext(new Draft());
Console.WriteLine("\\\\ Calling method \"GoToNextStatus\" - Result: ");
lDocumentContext.GoToNextStatus();
Console.WriteLine("\n\r\\\\ Calling method \"GoToNextStatus\" - Result: ");
lDocumentContext._DocumentContent = "Lorem ipsum";
lDocumentContext.GoToNextStatus();
Console.WriteLine("\n\r\\\\ Calling method \"GoToNextStatus\" - Result: ");
lDocumentContext._DocumentContent = "Lorem ipsum dolor sit amet";
lDocumentContext.GoToNextStatus();
Console.WriteLine("\n\r\\\\ Calling method \"GoToNextStatus\" - Result: ");
lDocumentContext.GoToNextStatus();
Console.WriteLine("\n\r\\\\ Calling method \"GoToNextStatus\" - Result: ");
lDocumentContext.GoToNextStatus();
}
}
public abstract class DocumentState
{
public abstract void GoToNextStatus(DocumentContext prDocumentContext);
public abstract void Close(DocumentContext prDocumentContext);
public abstract void Publish(DocumentContext prDocumentContext);
}
public class Draft : DocumentState
{
public override void GoToNextStatus(DocumentContext prDocumentContext)
{
if (string.IsNullOrWhiteSpace(prDocumentContext._DocumentContent))
Console.WriteLine("Is not possible to send a document with empty content for review");
else
{
Console.WriteLine("Document submitted to review");
prDocumentContext.DocumentState = new InReview();
}
}
public override void Close(DocumentContext prDocumentContext)
{
Console.WriteLine("Is not possible to close a document in the status \"Draft\"");
}
public override void Publish(DocumentContext prDocumentContext)
{
Console.WriteLine("Is not possible to publish a document in the status \"Draft\"");
}
}
public class InReview : DocumentState
{
public override void GoToNextStatus(DocumentContext prDocumentContext)
{
if (prDocumentContext._DocumentContent.Length < 15)
{
Console.WriteLine("Document rejected as the content has less than 15 characters");
prDocumentContext.DocumentState = new Rejected();
}
else
{
Console.WriteLine("Review approved");
prDocumentContext.DocumentState = new Approved();
}
}
public override void Close(DocumentContext prDocumentContext)
{
Console.WriteLine("Document closed");
prDocumentContext.DocumentState = new Closed();
}
public override void Publish(DocumentContext prDocumentContext)
{
Console.WriteLine("Is not possible to publish a document in the status \"In Review\"");
}
}
public class Approved : DocumentState
{
public override void GoToNextStatus(DocumentContext prDocumentContext)
{
Publish(prDocumentContext);
}
public override void Close(DocumentContext prDocumentContext)
{
Console.WriteLine("Document closed");
prDocumentContext.DocumentState = new Closed();
}
public override void Publish(DocumentContext prDocumentContext)
{
Console.WriteLine("Document published");
prDocumentContext.DocumentState = new Published();
}
}
public class Rejected : DocumentState
{
public override void GoToNextStatus(DocumentContext prDocumentContext)
{
Console.WriteLine("Document already in the last status (Rejected)");
}
public override void Close(DocumentContext prDocumentContext)
{
Console.WriteLine("Is not possible to close a rejected document");
}
public override void Publish(DocumentContext prDocumentContext)
{
Console.WriteLine("Is not possible to publish a document in the status \"Rejected\"");
}
}
public class Published : DocumentState
{
public override void GoToNextStatus(DocumentContext prDocumentContext)
{
Console.WriteLine("Document already in the last status (Published)");
}
public override void Close(DocumentContext prDocumentContext)
{
Console.WriteLine("Is not possible to close a published document");
}
public override void Publish(DocumentContext prDocumentContext)
{
Console.WriteLine("Document already published");
}
}
public class Closed : DocumentState
{
public override void GoToNextStatus(DocumentContext prDocumentContext)
{
Console.WriteLine("Document already in the last status (Closed)");
}
public override void Close(DocumentContext prDocumentContext)
{
Console.WriteLine("Document already closed");
}
public override void Publish(DocumentContext prDocumentContext)
{
Console.WriteLine("Is not possible to publish a closed document");
}
}
public class DocumentContext
{
private DocumentState _DocumentState;
public string _DocumentContent;
public DocumentContext(DocumentState prDocumentState)
{
_DocumentState = prDocumentState;
}
public DocumentState DocumentState
{
get { return _DocumentState; }
set
{
if (value != _DocumentState)
{
Console.WriteLine($"<< Document state changed from {_DocumentState.GetType().Name} to {value.GetType().Name} >>");
_DocumentState = value;
}
}
}
public void GoToNextStatus() { _DocumentState.GoToNextStatus(this); }
public void Close() { _DocumentState.Close(this); }
public void Publish() { _DocumentState.Publish(this); }
}
Output
Source Code ๐ฒ
ย