CSC/ECE 517 Fall 2012/ch2a 2w21 ap: Difference between revisions
Line 41: | Line 41: | ||
*[http://userpages.umbc.edu/~tarr/dp/lectures/StateStrategy.pdf]A bank account can change from an open account to a closed account and back to an open account again. The behavior of the two types of accounts is different. | *[http://userpages.umbc.edu/~tarr/dp/lectures/StateStrategy.pdf]A bank account can change from an open account to a closed account and back to an open account again. The behavior of the two types of accounts is different. | ||
*A chocolate vending machine which can have states like waiting for coins, has coin, sold, sold out. There are actions performed for transitioning among the states like insert coins, dispense chocolate, return coin. | *A chocolate vending machine which can have states like waiting for coins, has coin, sold, sold out. There are actions performed for transitioning among the states like insert coins, dispense chocolate, return coin. | ||
*[http://userpages.umbc.edu/~tarr/dp/lectures/StateStrategy.pdf]A simplified version of the Post Office Protocol used to download e-mail from a mail server. The code can be in states QUIT, HAVE_USER_NAME, START and AUTHORIZED and actions for transitioning between these states can be USER username, PASS password, LIST <message number>, RETR <message number> and QUIT. | *[http://userpages.umbc.edu/~tarr/dp/lectures/StateStrategy.pdf]A simplified version of the Post Office Protocol used to download e-mail from a mail server. The code can be in states QUIT, HAVE_USER_NAME, START and AUTHORIZED and actions for transitioning between these states can be USER username, PASS password, LIST <message number>, RETR <message number> and QUIT. | ||
Revision as of 01:29, 27 October 2012
Design patterns are convenient ways of reusing object-oriented code between projects and between programmers. The idea behind design patterns is to write down and catalog common interactions between objects that programmers have frequently found useful. The design patterns are divided into creational patterns, structural patterns and behavioral patterns.
Behavioral Patterns
[1][2]Behavioral patterns help you to define the communication between objects in your system and also specify how the flow is controlled in a complex program. These patterns are concerned with interactions between the objects. The interactions between the objects should be such that they are talking to each other and still are loosely coupled. This helps in avoiding dependencies and hard-coding.
State Pattern
[3] State pattern is a behavioral software design pattern where behavior of any object depends upon current state of the object. A monolithic object's behavior is a function of its state, and it must change its behavior at run-time depending on that state. If an object has multiple states and corresponding behaviors, the class becomes too complex with numerous conditional statements if all the transitions are included as the functions of the same class. Also, it becomes difficult to incorporate more states in the same structure.
Therefore, to make the code more clean and modular, only state is included as a property of the object and behavior for each transition is encapsulated in the separate class. When an object's internal state changes, its behavior is changed dynamically. Object appears to change its class.
Static conditional statements are replaced by a finite state machine which decides the transition flow of the object.
Examples
We should use the State pattern in the following scenario:
- An object's behavior depends on its state, and it must change its behavior at run-time depending on that state
- Operations have large, multipart conditional statements that depend on the object's state. The State pattern puts each branch of the conditional in a separate class.
A few scenarios in which the state pattern can be used:
- Consider an implementation of XOR gate used in logic. XOR gate outputs 1 when both the inputs are 1 or both the inputs are 0. It outputs 0 when one input is 0 and one input is 1.
Application of state pattern for XOR gate:
Consider two states, ZERO and ONE.
If the system is initially in state ZERO:
If the input message is 0, system goes into state ONE.
If the input message is 1, state does not change.
If system is initially in state ONE:
If the input message is 0, system goes into state ZERO.
If the input message is 1, state of the system does not change.
- [4]A bank account can change from an open account to a closed account and back to an open account again. The behavior of the two types of accounts is different.
- A chocolate vending machine which can have states like waiting for coins, has coin, sold, sold out. There are actions performed for transitioning among the states like insert coins, dispense chocolate, return coin.
- [5]A simplified version of the Post Office Protocol used to download e-mail from a mail server. The code can be in states QUIT, HAVE_USER_NAME, START and AUTHORIZED and actions for transitioning between these states can be USER username, PASS password, LIST <message number>, RETR <message number> and QUIT.
Class Diagram
[6] There is a Context class which communicates with the outside world. This class maintains the state of the corresponding object. It can have a number of internal states. The Context class is also called as Wrapper class. An interface State defines a common interface for all the concreate states. The states all implement the same interface; thus they are interchangeable. Our code can be in one of these states at a time.
State transition logic can be defined either in the wrapper class or in each individual state subclass. If it is included in wrapper class, structure becomes static, i.e., we can’t dynamically add new states to the structure. On the other hand, if it is included in each individual class, it results in increased coupling.
A Real Life Example
Scenario
Consider an example of a bulb which works in three modes. Off, dim and normal. Initially, the bulb is in off state. When we turn the switch, it glows and goes into dim state. If we turn the switch again, it goes into normal state. It again goes into off state on turning the switch.
A Possible Java Implementation
package patterns; class LightStateContext { private int currentState; public LightStateContext() { currentState = 0; } public void turnSwitch(){ if (currentState == 0){ currentState = 1; System.out.println("change to dim state."); } else if (currentState == 1){ currentState = 2; System.out.println("change to normal state."); } else if (currentState == 2){ currentState = 0; System.out.println("change to off state."); } } } public class InefficientCodeDemo{ public static void main(String[] args) { LightStateContext context = new LightStateContext(); while (true) { context.turnSwitch(); } } }
The class turnSwitch acts as finite state machine for this scenario. It contains the conditional logic for state transitions. Lots of 'if else' statements make the code unnecessarily complex. Also, to add another state for the bulb, we need to change the original lightStateContext class which makes this code inefficient and unavailable for extension.
A Better Solution
A better solution can be provided using state pattern. We can clearly identify 3 states of the bulb, off, dim and normal. We can also formulate the logic for finite state machine.
- If light is in 'off' state and we turn the switch, resulting state is 'dim'.
- If light is in 'dim' state and we turn the switch, resulting state is 'normal'.
- If light is in 'normal' state and we turn the switch, resulting state is 'off'.
Steps to Implement State Pattern
- Identify the states and define values for each state (typically constants)
- Create an instance variable that holds the current state.
- Identify all the actions that can occur in the system and find out all the actions that can cause state transition.
- Create a class that acts as the state machine.
- For each action, create a method that uses conditional statements to determine what behavior is appropriate in each state. You can also transition to another state in the conditional statement.
Java Implementation Using State Pattern
- Class LightStateContext acts as finite state machine for this example. This class contains the state variable 'currentState'. It includes the action 'turnSwitch' and a method 'setCurrentState' to set the state of the bulb when turnSwitch is called.
- state interface contains turnSwitch method which is called by the context class.
- A class is created for each individual state. These classes implement state interface and turnSwitch method of state interface is overridden by these classes.
package patterns; class LightStateContext { private State currentState; public LightStateContext() { currentState = new OffState(); } public State getCurrentState() { return currentState; } public void setCurrentState(State currentState) { this.currentState = currentState; } public void turnSwitch(){ currentState.turnSwitch(this); } } interface State{ void turnSwitch(LightStateContext context); } class OffState implements State{ @override public void turnSwitch(LightStateContext context) { context.setCurrentState(new DimState()); System.out.println("change to dim state."); } } class DimState implements State{ @Override public void turnSwitch(LightStateContext context) { context.setCurrentState(new NormalState()); System.out.println("change to normal state."); } } class NormalState implements State{ @Override public void turnSwitch(LightStateContext context) { context.setCurrentState(new OffState()); System.out.println("change to off state."); } } public class StatePatternDemo { public static void main(String[] args) { LightStateContext context = new LightStateContext(); while (true) context.turnSwitch(); } }
Advantages
[7] Advantages of the state pattern can be summarized as:
- One object for one state.
- Allows state transition logic to be be incorporated into a state object rather than in a monolithic if or switch statement
- Helps avoid inconsistent states since state changes occur using just the one state object and not several objects or attributes
- By using objects we can make the states explicit and reduce the effort needed to understand and maintain the code.
- If the state pattern is implemented correctly, the code becomes easy to extend.
Let us assume we are asked to show that when the bulb is in the normal state and we turn the switch the bulb glows bright. To incorporate this kind of change we need to:
1. Add a new BrightState that implements the State interface
class BrightState implements State{ @Override public void turnSwitch(LightStateContext context) { context.setCurrentState(new OffState()); System.out.println("change to off state."); } }
2. In the previous state's (NormalState) turnSwitch method set the current state to BrightState
context.setCurrentState(new BrightState());
Limitations
- Too many objects are created. This is a price that we need to pay for better flexibility and maintainability.
- Becomes too heavy when Finite State Machine is not that complex.
State Pattern Vs Strategy Pattern
[9]A Strategy pattern is another behavioral software design pattern which separates the behavioral algorithms from the object. Each algorithm is encapsulated in a different class. Depending upon the properties of the current object, decision of invoking an algorithm is taken at runtime.
The class diagrams of these two patterns are similar in structure. However, there are a few differences between these patterns.
- The patterns differ in their intent. In a strategy pattern, the client specifies the strategy object that the client is composed with. There is a strategy object that is most appropriate for the context object. For example, Two sorting algorithms (Merge Sort and Quick sort) are implemented and the client can select either of the algorithms for sorting a list. In a state pattern, we have a set of behaviors encapsulated in state objects, at any time the context is delegating to one of those states. The current state changes with every action to reflect the internal state of the context. The client usually knows very little about the state objects.
- In a strategy pattern, once a decision is made to invoke a particular algorithm, it is not possible to change it. Whereas in state pattern, transition between states occurs at runtime.
- In state pattern, decision of which state to invoke depends only on one variable.
- We can say that state pattern is a type of strategy pattern where each state represents a different behavioral algorithm for the object in context.
A class that performs validation on incoming data may use a strategy pattern to select a validation algorithm based on the type of data, the source of the data, user choice, and/or other discriminating factors. These factors are not known for each case until run-time, and may require radically different validation to be performed. A state pattern can be used for implementing a drawing program. The program has many tools like pointer, fill shape which at any point in time can act as one of several tools. Instead of switching between multiple objects, the code maintains an internal state representing the tool currently in use.
References
- http://sourcemaking.com/behavioral_patterns
- http://www.allapplabs.com/java_design_patterns/behavioral_patterns.htm
- http://sourcemaking.com/design_patterns/state
- http://userpages.umbc.edu/~tarr/dp/lectures/StateStrategy.pdf
- http://userpages.umbc.edu/~tarr/dp/lectures/StateStrategy.pdf
- http://sourcemaking.com/design_patterns/state
- http://userpages.umbc.edu/~tarr/dp/lectures/StateStrategy.pdf
- https://docs.google.com/a/ncsu.edu/viewer?a=v&q=cache:UGImuHnhO8MJ:www.cs.toronto.edu/~arnold/407/06s/lectures/studentPresentations/stateStrategy/state_strat_pres.ppt+disadvantages+of+strategy+pattern&hl=en&gl=us&pid=bl&srcid=ADGEEShbX8h_8wQ7PkIoXMKwXjPgISI7dduhY-HrO8fUV8lntQw0RYYWQ-eG_hLAxTT3pjUj5j5Dj8F7-baC3D-C6Znv_YTujBdB_E6-WkZ9KMe2jWXGtZgeRtMcwEJtpqN8JNOC9itc&sig=AHIEtbSP_rpR12IcGL1KyQAhi0PGeUQqrQ&pli=1
- http://userpages.umbc.edu/~tarr/dp/lectures/StateStrategy.pdf
Further References
- Freeman,Freeman,Bates,Sierra,Robson.Head First Design Patterns,2004, O'Reilly
- http://www.freetechbooks.com/the-design-patterns-java-companion-t126.html