CSC/ECE 517 Fall 2012/ch1b 2w41 dc
State pattern and the related patterns
The State pattern allows an object to completely change its behavior and the change depends on its current internal state. Alternatively, a monolithic object's behavior is a function of its state, and it must change its behavior at run-time depending on that state. State pattern is closely related to Strategy pattern and Bridge pattern. We shall discuss the three patterns, their structures, advantages & disadvantages.
Description
In this section, each of the three patterns is discussed along with their structure and examples.
State Pattern
The state pattern is behavioral as it defines how communication between classes or entities is controlled. It is used in programming to define the state of an object. This pattern, also called as object for states pattern <ref>http://en.wikipedia.org/wiki/State_pattern</ref>, allows the class of an object to change at runtime without changing the interface used to access the object or losing the current state. This change in class is abstracted with the use of a wrapper object or context.<ref>http://www.blackwasp.co.uk/State.aspx</ref>
Creating object oriented state machines is one of the uses of the state pattern. In this, the functionality of the object changes fundamentally according to its state. Using multiple concrete classes, each class inheriting from the same base class is an alternative to multiple number of 'if' or 'switch' statements.
Structure
Following is the general structure of state pattern<ref>http://www.cs.umd.edu/class/fall2002/cmsc433-0101/Lectures/designPatterns2.pdf</ref>:
- Context: Used by the clients of the state pattern which do not access the state objects directly. It holds a ConcreteState object according to the current state.
- State: Abstract base class of all ConcreteState classes. No state is defined in this class or its subclasses.
- Concrete States: The concrete state classes implement the real functionality that will be used by the Context object. ConcreteState A, ConcreteState B etc. in the figure are the states of the Context and implement the Handle().
Example
- One of the most common examples for State pattern is implementation of an alarm clock. This implementation has four states: Off, On, Snooze and Buzz. The following figure depicts the state diagram of an alarm clock:<ref>http://mypages.valdosta.edu/dgibson/courses/cs4322/Lessons/State/stateNotes.pdf</ref>
- Consider the code in the block below. FooState and BarState are two states implementing the IState interface.
package patterncraft.state { public interface IState { function engage():void; } } package patterncraft.state { public class FooState implements IState{ private var main:Main; public function FooState(main:Main) { this.main = main; } public function engage():void{ main.sayFoo() } } } package patterncraft.state { public class BarState implements IState{ private var main:Main; public function BarState(main:Main) { this.main = main; } public function engage():void{ main.sayBar(); } } } package { import flash.display.Sprite; import patterncraft.state.IState import patterncraft.state.FooState; import patterncraft.state.BarState; public class Main extends Sprite { public function Main() { var state:IState = new FooState(this); state.engage(); state = new BarState(this); state.engage(); } public function sayFoo():void { trace("foo") } public function sayBar():void { trace("bar") } } }
We see that the engage method is called for each of the instance of FooState and BarState. These instances have been created using the instance of the Main class which is calling these methods inside it. As from the example we see that this pattern allows an object to alter its behavior using a context (here ‘Main’ class) when its state (here ‘state’ object) changes.
Strategy Pattern
Strategy pattern allows a set of similar algorithms to be defined and encapsulated in their own classes. This pattern is used to create multiple interchangeable family of algorithms and a specific algorithm can be selected at run time according to the configuration details or user preferences. It increases flexibility as new algorithms can be added easily.
Structure
Following is the general structure of Strategy pattern:<ref>http://www.blackwasp.co.uk/Strategy.aspx</ref>
- Client: This is the user of interchangeable algorithm which has a property to hold one of the strategy classes selected at runtime.
- StrategyBase: This is an abstract base class for all the classes which can include multiple methods. This can also be implemented as an interface.
- ConcreteStrategy A/B: Each of the ConcreteStrategy classes implement one algorithm which can be used by the client.
Example
- One of the most common examples of Strategy pattern is File Encryption. For encrypting a small file, in-memory strategy can be used, which reads the whole file into memory. Whereas for a large file, parts of file are read into the memory and encrypted partial results are stored in temporary files.
- Consider the code in the block below. FooStrategy and BarStrategy are two different strategies derived from the IStrategy interface.
package patterncraft.strategy { public interface IStrategy { function engage():void; } } package patterncraft.strategy { public class Container { public var engageBehavior:IStrategy; public function Container() { } public function engage():void { engageBehavior.engage(); } } } package patterncraft.strategy { public class FooStrategy implements IStrategy { private var container:Container; public function FooStrategy(container:Container) { this.container = container; } public function engage():void { trace("foo") } } } package patterncraft.strategy { public class BarStrategy implements IStrategy { private var container:Container; public function BarStrategy(container:Container) { this.container = container; } public function engage():void { trace("bar") } } } package { import flash.display.Sprite; import patterncraft.strategy.Container; import patterncraft.strategy.IStrategy; import patterncraft.strategy.FooStrategy; import patterncraft.strategy.BarStrategy; public class Main extends Sprite { public function Main() { var container:Container = new Container(); var strategy:IStrategy = new FooStrategy(container); container.engageBehavior = strategy; container.engage(); container.engageBehavior = new BarStrategy(container); container.engage(); } } }
The algorithm for each strategy is encapsulated in each of the two classes. Container is a context that switches between strategies FooStrategy and BarStrategy using the engageBehavior method. It is clear that State is similar to Strategy, just that the intent of each of these patterns is different as has been discussed already.
Bridge Pattern
Bridge pattern separates abstract elements of a class from its implementation. This can be used to achieve cleaner implementation of real world objects and it allows easy changes in implementation. For instance, business logic of an element can be the abstract elements of a class which can be created independent of the implementation details of their data access. This makes the business logic independent of databases etc.
Unlike State pattern, Bridge pattern is structural as it defines how relationships can be created between classes or entities.
Structure
Following is the general structure of Bridge pattern:<ref>http://www.blackwasp.co.uk/Bridge.aspx</ref>
- Abstraction: This is a base class for other abstractions and it contains members that define abstract business objects. An object of this type holds a reference to a particular implementation for different platform specific applications.
- RefinedAbstraction: Each RefinedAbstraction provides more specific implementation of Abstraction.
- ImplementationBase: This is an abstract class and acts as a base class for all classes providing implementation. This could be defined as an interface if no functionality is being provided for its subclasses.
- ConcreteImplementation: This is responsible for providing platform specific functionality.
Example
- The most common example of a bridge pattern is Device Drivers. Device vendors would need interface specifications and they are defined using bridge pattern.
- Consider the code in the block below. IBridge provides an interface for FooBridge and BarBridge.
package patterncraft.bridge { public interface IBridge { function engage():void; } } package patterncraft.bridge { public class FooBridge implements IBridge{ public function FooBridge() { } public function engage():void{ trace("foo") } } } package patterncraft.bridge { public class BarBridge implements IBridge{ public function BarBridge() { } public function engage():void{ trace("bar") } } } package { import flash.display.Sprite; import patterncraft.bridge.IBridge; import patterncraft.bridge.FooBridge; import patterncraft.bridge.BarBridge; public class Main extends Sprite { public function Main() { var bridge:IBridge = new FooBridge(); bridge.engage(); bridge = new BarBridge(); bridge.engage(); } } }
Each of these two classes implement the IBridge interface. engage() method is called on instances of both the objects and each of them has a different implementation of the method. We see that these method calls are independent to each other and the main method from which they are being called.
Chain of Responsibility Pattern
Chain of Responsibility pattern helps decouple the sender of a request and receiver of a request in a chain of multiple handler objects. When a system receives a request, only one handler object from its chain of handlers can process the request. If the object however cannot serve the request then it will determine the next handler object in the chain of responsibility and push the request forward in the chain. In the chain of handler objects, the responsibility of determining who to serve the request is left to the objects participating in the chain.<ref>http://tinyurl.com/brkg9py</ref>
Structure
Following is the general structure of Chain of Responsibility:<ref>http://www.dofactory.com/Patterns/PatternChain.aspx</ref>
- Handler: This is a base class for ConcreteHandler objects that defines an interface for handling the requests. It may or may not implement the successor link.
- ConcreteHandler: These are the request handler objects that constitute the chain of responsibility. It handles the requests sent to it by a Client or another ConcreteHandler object. If the ConcreteHandler can handle the request it does so; otherwise is will forward the request to its successor. It can access its successor.
- Client: This initiates the request to a ConcreteHandler object in the chain of Handler that may handle the command.
Example
Exception Handling in Java uses chain of responsibility in deciding how to handle an exception. A sequence of exceptions is listed in catch statements and when there is an exception thrown, this list is scanned one by one from top. If a catch statement can handle the exception then the job is done, otherwise it is passed to the next catch block and so on until it reaches the finally block.
Comparison
The State, Bridge and Strategy patterns provide similar solution structures. But the intent of each of these patterns is different and hence solve different problems. The major differences between each of the patterns have been discussed:
State Pattern and Bridge Pattern
The structure of State and Bridge is identical and the only difference lies in how they address these problems.
- The state pattern is used to address problems that have state dependent behavior. The bridge is a structural pattern with an interface and two or more implementations types and allows to swap between those types and use the different functionality.
- The state pattern allows an object’s behavior to change along with its state. The bridge pattern is used for an implementation of an abstraction. It governs how different states and classes interact with each other.
State Pattern and Strategy Pattern
Following are the differences between State and Strategy patterns:
- State changes from within states whereas strategies are changed from outside.
- A strategy encapsulates the complete algorithm whereas a state encapsulates a set of behaviors appropriate to that state.
- Strategies are interchangeable, states are not.
- Strategies are not linked to other strategies, whereas states are frequently linked to other states.
- A strategy is active in the sense that it encompasses the idea of processing the state. A state is passive.
Bridge Pattern and Strategy Pattern
Following are the differences between Bridge and Strategy patterns:
- Strategy pattern is meant for behavior, while bridge pattern is meant for structure.
- Bridge pattern focuses on object composition while Strategy pattern deals with collaboration between objects.
State Pattern and Chain of Responsibility Pattern
State pattern can be combined with Chain of Responsibility when one or the other has already been applied in a system. The two patterns can be used as larger building blocks in design, thus raising the abstraction level. The state design pattern can be organized in a chain of responsibility.
Conclusion
The State, Strategy and Bridge patterns belong to different classes of design patterns. Bridge is a structural design pattern and State and Strategy are behavioral design patterns. Different design patterns can be combined for designing of important abstractions of the application domain. Since the three patterns primarily discussed here solve similar kinds of problems, understanding the complex relationships between them will help in applying a specific pattern or a combination of patterns. No pattern has advantages over using another, but the intent of the pattern should be capable of providing a fitting solution to the problem.
References
<references/>