Learn about the State Design Pattern in Java

Tram Ho

Introduce

In fact, there are many problems related to states, such as order status, playing music status, content status through processes … In cases like this, It is impossible not to mention the State Design Pattern, this design pattern will help us to design the structure, handle the state-related logic more easily and professionally. Today we will learn about State Design Pattern (State Design Pattern), specifically how it works, how to implement this design pattern in Java.
First, we will give an overview of its purpose and explain the problem it tries to solve. Later, we’ll find its UML chart type and implement the actual example.

Overview of State Design Pattern

The main idea of ​​the State design pattern is that it allows objects to change their behavior and state without changing its class. Also, by implementing it, the code will be cleaner and more beautiful without the need for many if / else statements.
Imagine we have a package ( package ) is sent to the post office, the package can be ordered ( order ), then sent to the post office and get the last customer. Now, depending on the actual state, we want to print its delivery status.
The simplest approach is to add some boolean flags and apply simple if / other statements in each of our methods in the class. That won’t complicate it much in a simple scenario. However, it can be complicated and confusing in our code as we will handle more states, which will result in more if / other statements.
In addition, all the logic for each state is spread evenly across all methods. Now, this is where State designs can be considered. Thanks to the State design pattern, we can encapsulate the logic in specialized classes, apply the Single Responsibility Principle and the Open-closed principle , the code will be cleaner and easier to maintain.

UML chart

Take a look at the UML diagram for this design pattern:

In the UML diagram, we see that the Context class has a linked State that changes during program execution.
Context will delegate state execution behavior. In other words, all behaviors will be handled by a specific implementation ( handle method) of the state.
We see that the logic is separated and adding new states is simple – it is also possible to add other states if needed.

Implementation

Now let’s learn how to implement this design, as mentioned above our object is the package ( package ), which has the following status: order ( order ), delivery ( delivered ) and receive the goods ( received ). So we will have 3 states for the context class (here is the package )
First, the context definition, in this particular example, is the Package class:

A little more interested in this class, our Package class will contain a state object (it is PackageState ), PackageState will be an interface representing the three states mentioned above: OrderedState , DeliveredState and ReceivedState . The Package class implements three methods related to the state: previousState (revert to the previous state), nextState (move to the next state) and printStatus (notify the current status of the package), starting from OrderedState status.
Next, we will have a PackageState interface that has three methods as follows:

This interface will be implemented by 3 states corresponding to 3 classes: OrderedState , DeliveredState and ReceivedState :
OrderedState class:

OrderedState is the first state of the package, it cannot be returned to the previous state, but can move to the next state which is DeliveredState
DeliveredState class:

DeliveredState is the second state of the package in the above example, it can revert to the previous state of OrderedState , and can also switch to the next state ReceivedState .
ReceivedState class:

ReceivedState is the final state of the package, it can only return to the previous state DeliveredState .

Testing

Let’s see how. First, verify that the setup transitions work as expected with a few small tests:

Next, quickly check if our package can return to its status:

Then, verify the state change and see how the implementation of the printStatus() method changes its implementation at runtime:

And here is the output:

Limit

State template restriction is the implementation of transitioning between states. That makes the state hardcoded, which is a generally bad practice.
However, depending on our needs and requirements, it may or may not be a problem.

Conclude

State designs are great when we want to avoid common if / else statements. Instead, we extract the logic to separate the classes and let our context object delegate behavior to the methods implemented in the state class. Besides, we can take advantage of transitions between states, in which a state can change the state of the context.

Refer

State Design Pattern in Java – Baeldung

Share the news now

Source : Viblo