Understanding the State Pattern with Calculator
🛠 Introduction
The State Pattern allows an object to change its behavior dynamically based on its internal state. It’s a powerful design pattern for handling complex, state-dependent behavior in an organized and maintainable way.
In this article, we’ll explore the State Pattern by implementing a simple Calculator with multiple states.
📚 Calculator State Example
1️⃣ State Interface
The State interface defines the contract that all concrete state classes must implement. It contains methods that represent the state-specific behavior.
public interface ICalculatorState {
void EnterNumber(CalculatorContext context, int number);
void PerformOperation(CalculatorContext context, string operation);
}
2️⃣ Concrete States
Concrete states implement the State interface. Each state encapsulates the behavior for a specific condition of the Context.
NumberState: Handles behavior when the calculator expects a number.
public class NumberState : ICalculatorState {
public void EnterNumber(CalculatorContext context, int number) {
context.CurrentValue = number;
Console.WriteLine($"Number entered: {number}");
}
public void PerformOperation(CalculatorContext context, string operation) {
Console.WriteLine("Operation not allowed in Number State.");
}
}
OperationState: Handles behavior when the calculator performs an operation.
public class OperationState : ICalculatorState {
public void EnterNumber(CalculatorContext context, int number) {
context.SecondValue = number;
Console.WriteLine($"Second number entered: {number}");
}
public void PerformOperation(CalculatorContext context, string operation) {
switch (operation) {
case "+":
context.Result = context.CurrentValue + context.SecondValue;
break;
case "-":
context.Result = context.CurrentValue - context.SecondValue;
break;
default:
Console.WriteLine("Unsupported operation.");
return;
}
Console.WriteLine($"Operation performed: {context.Result}");
context.SetState(new NumberState()); // Transition back to NumberState
}
}
3️⃣ Context
The Context is the core class that ties everything together. It keeps track of the current state and delegates behavior to the current state object.
public class CalculatorContext {
private ICalculatorState _state;
public int CurrentValue { get; set; }
public int SecondValue { get; set; }
public int Result { get; set; }
public CalculatorContext() {
_state = new NumberState(); // Start in the NumberState
}
public void SetState(ICalculatorState state) {
_state = state;
}
public void EnterNumber(int number) {
_state.EnterNumber(this, number);
}
public void PerformOperation(string operation) {
_state.PerformOperation(this, operation);
}
}
4️⃣ Main Program
Here’s how it all comes together in the main program:
class Program {
static void Main(string[] args) {
CalculatorContext calculator = new CalculatorContext();
calculator.EnterNumber(10);
calculator.SetState(new OperationState());
calculator.EnterNumber(20);
calculator.PerformOperation("+");
}
}
Output :
Number entered: 10
Second number entered: 20
Operation performed: 30
✅ Conclusion
The State Pattern is an effective solution for managing state-dependent behavior in software applications. By encapsulating state-specific logic within individual classes, it promotes cleaner, modular, and maintainable code.
The Calculator example demonstrates how this pattern allows dynamic state transitions, ensuring the application behaves correctly as its state evolves. This approach is especially useful in scenarios requiring flexibility and extensibility, such as games, workflows, or applications with complex user interactions.
Top comments (0)