Behavioral Design Patterns provide solution for the better interaction between objects and how to provide lose coupling and flexibility to extend easily. Following design patterns come under this category.
State pattern lets you change the behavior of a class when the state changes.
State design pattern is used when an Object change its behavior when it’s internal state changes.
The state of an object can be defined as its exact condition at any given point of time, depending on the values of its properties or attributes. The set of methods implemented by a class constitutes the behavior of its instances. Whenever there is a change in the values of its attributes, we say that the state of an object has changed.
When a Context object is first created, it initializes itself with its initial State object. This State object becomes the current State object for the context. By replacing the current State object with a new State object, the context transitions to a new state. When an application object makes a call to a Context method (behavior), it forwards the method call to its current State object.
The benefits of using State pattern to implement polymorphic behavior is clearly visible. The chances of error are less and it’s very easy to add more states for additional behavior. Thus making our code more robust, easily maintainable and flexible. Also State pattern helped in avoiding if-else
or switch-case
conditional logic in this scenario.
Let's take a look at the diagram definition before we go into more detail.
request()
method is called on the Context, the message is delegated to the State to handle.When to use the State design pattern
Java
Let's look at an example of the state pattern. First off, we'll define the EmotionalState
interface. It declares two methods, sayHello()
and sayGoodbye()
.
File EmotionalState.java.
// State public interface EmotionalState { public String sayHello(); public String sayGoodbye(); }
The HappyState
class is a Concrete State that implements sayHello()
and sayGoodbye()
of EmotionalState
. These messages are cheerful (representing a happy state).
File HappyState.java.
// Concrete State public class HappyState implements EmotionalState { @Override public String sayGoodbye() { return "Bye, friend!"; } @Override public String sayHello() { return "Hello, friend!"; } }
The SadState
class also implements the EmotionalState
interface. The messages are sad (representing a sad state).
File SadState.java.
//Concrete State public class SadState implements EmotionalState { @Override public String sayGoodbye() { return "Bye. Sniff, sniff."; } @Override public String sayHello() { return "Hello. Sniff, sniff."; } }
The Person
class is the Context class. It contains an EmotionalState
reference to a concrete state. In this example, we have Person
implement the EmotionalState
reference, and we pass the calls to Person
's sayHello()
and sayGoodbye()
methods on to the corresponding methods on the emotionalState
reference. As a result of this, a Person
object behaves differently depending on the state of Person
(ie, the current EmotionalState
reference).
File Person.java.
// Context public class Person implements EmotionalState { EmotionalState emotionalState; public Person(EmotionalState emotionalState) { this.emotionalState = emotionalState; } public void setEmotionalState(EmotionalState emotionalState) { this.emotionalState = emotionalState; } @Override public String sayGoodbye() { return emotionalState.sayGoodbye(); } @Override public String sayHello() { return emotionalState.sayHello(); } }
The Demo
class demonstrates the state pattern. First, it creates a Person
object with a HappyState
object. We display the results of sayHello()
and sayGoodbyte()
when the person object is in the happy state. Next, we change the person object's state with a SadState
object. We display the results of sayHello()
and sayGoodbyte()
, and we see that in the sad state, the person object's behavior is different.
File Demo.java.
public class Demo { public static void main(String[] args) { Person person = new Person(new HappyState()); System.out.println("Hello in happy state: " + person.sayHello()); System.out.println("Goodbye in happy state: " + person.sayGoodbye()); person.setEmotionalState(new SadState()); System.out.println("Hello in sad state: " + person.sayHello()); System.out.println("Goodbye in sad state: " + person.sayGoodbye()); } }
Python 3
import abc class EmotionalState(metaclass=abc.ABCMeta): @abc.abstractmethod def say_hello(self): pass @abc.abstractmethod def say_goodbye(self): pass class HappyState(EmotionalState): def say_goodbye(self): return "Bye, friend!" def say_hello(self): return "Hello, friend!" class SadState(EmotionalState): def say_goodbye(self): return "Bye. Sniff, sniff." def say_hello(self): return "Hello. Sniff, sniff." class Person(EmotionalState): def __init__(self, state): self.state = state def set_state(self, state): self.state = state def say_goodbye(self): return self.state.say_goodbye() def say_hello(self): return self.state.say_hello() if __name__ == '__main__': person = Person(HappyState()) print("Hello in happy state: " + person.say_hello()) print("Goodbye in happy state: " + person.say_goodbye()) person.set_state(SadState()) print("Hello in sad state: " + person.say_hello()) print("Goodbye in sad state: " + person.say_goodbye())