-
StateModeling/DesignPattern 2020. 2. 26. 00:43
1. Overview
State pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. This pattern is close to the concept of finite-state machines. The state pattern can be interpreted as a strategy pattern, which is able to switch a strategy through invocations of methods defined in the pattern's interface.
- State design pattern allows our objects to behave differently based on its current internal state. This pattern allows defining state-specific behaviors in separate classes.
- Operations defined in the class delegate to the current state object's implementation of that behavior.
- State transitions can be triggered by states themselves in which case each state knows about at least one other state's existence.
- A benefit of this pattern is that new states and thus new behaviors can be added without changing our main class.
2. Description
2.1 Implementation
- Identify distinct values for the state fo our object (context). Each state value will be a separate class in our implementation. These classes will provide behavior specific to the state value they represent.
- In our main/context class method implementations we'll delegate the operation to the current state object.
- We have to decide how our state transition is going to happen. States can themselves transition to the next state based on input received in a method. Another option is context itself can initiate the transition.
- The client interacts with our main class or context and is unaware of the existence of a state.
2.2 Consideration
2.2.1 Implementation
- In some implementations, clients themselves can configure context with an initial state. However, after that, the state transition is handled either by states or context.
- If state transitions are done by state object itself then it has to know about at least one state. This adds to the amount of code change needed when adding new states.
2.2.2 Pitfalls
- A lot more classes are created for providing the functionality of context and all those need unit testing as well
- State transitions can be a bit tricky to implement. This becomes more complicated if there multiple possible states to which object can transition from the current state. And if states are responsible for triggering transitions when we have a lot more coupling between states
- We may not realize all the possible states we need at the beginning of our design. As our design evolves we may need to add more states to handle a particular behavior
3. Usage
- Java Server Faces (JSF) framework's LifeCycle implementation
4. Comparison with Command
State Command Implements actual behavior of an object-specific to a particular state Command execution simply calls a specific operation on receiver A state object represents the current state of our context object Command represents an operation or request without any direct relation to the state of receiver 5. Example
//Context class class Order { private OrderState currentState; public Order() { this.currentState = new New(); } public double cancel() { double charges = currentState.handleCancellation(); currentState = new Cancelled(); return charges; } public void paymentSuccessful() { // transition one state to another currentState = new Paid(); } public void dispatched() { currentState = new InTransit(); } public void delivered() { currentState = new Delivered(); } } class New implements OrderState{ @Override public double handleCancellation() { System.out.println("It's a new Order. No processing done"); return 0; } } class Paid implements OrderState { @Override public double handleCancellation() { System.out.println("Contacting payment gateway to rollback transaction"); return 10; } } class InTransit implements OrderState { @Override public double handleCancellation() { System.out.println("Contacting courier service for cancellation"); System.out.println("Contacting payment gateway for transaction roll back"); return 20; } } class Delivered implements OrderState { @Override public double handleCancellation() { System.out.println("Contacting courier service for item pickup"); System.out.println("Payment roll back will be initiated upon receiving returned item"); return 30; } } class Cancelled implements OrderState{ @Override public double handleCancellation() { // call cancel already canceled object throw new IllegalStateException("Cancelled order. Can't cancel anymore"); } } //Abstract state interface OrderState { double handleCancellation(); } public class Client { public static void main(String[] args) { Order order = new Order(); // order.cancel(); order.paymentSuccessful(); order.cancel(); } }
6. Reference
'Modeling > DesignPattern' 카테고리의 다른 글
Open-Closed Principle (OCP) (0) 2020.02.26 Single Responsibility Principle (SRP) (0) 2020.02.26 Strategy (0) 2020.02.26 Prototype (0) 2020.02.26 Facade (0) 2020.02.24