January 16, 2010 Design Patterns, Java
January 16, 2010 Design Patterns, Java
Imagine that you need to develop application for shipping Orders. Your Orders could be in few states: New Order, Registered, Granted, Shipped, Invoiced, Cancelled.
And there are some rules which allow your Order to migrate to another state. This means that for example you cannot ship not registered Order.
Also there are some behavioral rules. For example you cannot add new Product to your Order when it is in Cancelled state. Also behavioral rules could mean changes in state.
How could you accomplish this requirements easily?
We could encapsulate behavior which belongs to current object’s state into separate classes derived from some parent class. Each of the concrete will be responsible for allowing changing state from one to another.
State Pattern UML
How does it work?
At first our Order class has a reference to its _state, to have more real example Order also has _products.
private OrderState _state;
private List<Product> _products = new ArrayList<Product>();
public void setOrderState(OrderState state){
_state = state;
}
Order delegates some state-specific requests to the current state.
– If the current state is Granted, it changes Order‘s state to Shipped and if needed do some surrounded work or delegates it.
This code represents concrete implementation of the OrderState. Constructor of base class has Order parameter, so this allows us have reference to holding Order: _order in derived classes.
public Granted(Order holdingOrder) {
super(holdingOrder);
}
public void ship(){
_order.doShipping();
//next line changes Order’s state
_order.setOrderState(new Shipped(_order));
}
If you are care what method ship() is doing in Order class it could be like shipping :).
– If current state is Registered, most likely that class has no implementation of method ship(), it has only addProduct(), grant(), and cancel(). So method of super class will be called. OrderState has all bulk of methods but they all throw exceptions, which says that changing state in current situation is not allowed.
protected Order _order;
public OrderState(Order holdingOrder){
_order = holdingOrder;
}
public void ship(){
raiseNotAllowableOperation(“ship”);
}
//other methods like register(), grant(), etc… here..
//they look like the ship() looks
private void raiseNotAllowableOperation(String operation) throws IllegalStateException {
String stateName = this.getClass().getName();
System.out.println(“ERROR: Operation [“+operation+“] is not allowed for current order state: “ + stateName);
//of course in real system you will probably throw exception
//throw new IllegalStateException(“This operation is not allowed for current order state.”);
}
Example of Usage of Order class
Now we navigating to customer code. Our OrderingSystem creates new Order, adds some beer as product and all in correct way:
Output:
Ok, now we added code, which tries to add more beer when order has been already shipped.
Output:
Other ways to solve problem without State Pattern
One of the disadvantages of this you could see many of the classes needed to have:
Yes, but this is the way to greatly encapsulate your behavior. Also there are other ways to resolve problem. For example usage of the table [state|method|state] which is populated with all allowable transitions. You could also resolve issue with having switch-case method. About all of this you could read in Jimmy Nilsson’s book “Applying Domain-Driven Design and Patterns“.
What have I learned?
I hope you enjoyed this story.
Go to: My Design Patterns Table
Markdown | Result |
---|---|
*text* | text |
**text** | text |
***text*** | text |
`code` | code |
~~~ more code ~~~~ |
more code |
[Link](https://www.example.com) | Link |
* Listitem |
|
> Quote | Quote |
This pattern was always associated with finite machines in discrete mathematics for me. Thanks for new interesting sample of it's application.
Thanks for comment you are one of those persons who help me keep going.