Mastering the State Pattern: Real‑World Java Examples and Spring State Machine
This article explains the State (State Machine) pattern, its typical scenarios such as order processing and elevator control, presents a complete Java implementation with abstract, concrete, and context classes, demonstrates how to model order workflows using Spring State Machine, compares related patterns, and discusses the pattern’s advantages and drawbacks.
State Pattern (also called State Machine Pattern) lets an object change its behavior when its internal state changes, eliminating bulky if/else or switch statements.
Application Scenarios
Behavior changes with state.
Operations with many branches that depend on the object's state.
Typical examples include e‑commerce order status changes and elevator floor selection.
Core Roles
Context (maintains the current state and provides the client interface).
Abstract State (defines the behavior contract).
Concrete State (implements behavior and triggers state transitions).
Business Example – Article Interaction
When a user is logged in, actions such as comment, forward, and collect are allowed; otherwise the system redirects to the login page. The following Java code shows the abstract state and two concrete states.
<code>public abstract class UserState {
private AppContext appContext;
public void setAppContext(AppContext appContext) { this.appContext = appContext; }
public abstract void forward();
public abstract void collect();
public abstract void comment(String comment);
}
public class LoginState extends UserState {
@Override public void forward() { System.out.println("转发成功!"); }
@Override public void collect() { System.out.println("收藏成功!"); }
@Override public void comment(String comment) { System.out.println("评论成功,内容是:" + comment); }
}
public class UnLoginState extends UserState {
@Override public void forward() { forward2Login(); this.appContext.forward(); }
@Override public void collect() { forward2Login(); this.appContext.collect(); }
@Override public void comment(String comment) { forward2Login(); this.appContext.comment(comment); }
private void forward2Login() {
System.out.println("跳转到登录页面!");
this.appContext.setState(this.appContext.LOGIN_STATE);
}
}
public class AppContext {
public static final UserState LOGIN_STATE = new LoginState();
public static final UserState UNLOGIN_STATE = new UnLoginState();
private UserState currentState = UNLOGIN_STATE;
{ UNLOGIN_STATE.setAppContext(this); LOGIN_STATE.setAppContext(this); }
public void setState(UserState state) { this.currentState = state; this.currentState.setAppContext(this); }
public void forward() { this.currentState.forward(); }
public void collect() { this.currentState.collect(); }
public void comment(String comment) { this.currentState.comment(comment); }
}
</code>Spring State Machine for Order Flow
Spring’s StateMachine module simplifies order status management. The article lists the Maven dependency, entity classes, enums for status and events, configuration of states and transitions, a stub persistence implementation, a listener, service interface, and a thread‑safe service implementation.
<code><dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
public enum OrderStatus { WAIT_PAYMENT, WAIT_DELIVER, WAIT_RECEIVE, FINISH; }
public enum OrderStatusChangeEvent { PAYED, DELIVERY, RECEIVED; }
@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> {
@Override
public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception {
states.withStates().initial(OrderStatus.WAIT_PAYMENT).states(EnumSet.allOf(OrderStatus.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception {
transitions.withExternal().source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_DELIVER).event(OrderStatusChangeEvent.PAYED)
.and()
.withExternal().source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE).event(OrderStatusChangeEvent.DELIVERY)
.and()
.withExternal().source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH).event(OrderStatusChangeEvent.RECEIVED);
}
}
</code>Related Patterns
State vs. Chain of Responsibility – both reduce conditional logic; the former models internal state changes, the latter models a chain of external handlers.
State vs. Strategy – class structures are similar, but State involves automatic transitions while Strategy is selected explicitly by the client.
Advantages and Disadvantages
Advantages
Clear structure; eliminates bulky conditionals.
Explicit state classes make transitions more readable.
State classes have well‑defined responsibilities and are extensible.
Disadvantages
Potential class explosion when many states exist.
Complex implementation can lead to tangled code if misused.
Adding new states often requires modifying transition logic, weakening the Open/Closed Principle.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.