Fundamentals 15 min read

Mastering the State Pattern: Theory, Java Examples, and Real‑World Order Workflow

This article explains the State (State Machine) pattern, its typical scenarios, core roles, and provides complete Java implementations—including a user login example and a Spring StateMachine‑driven order processing workflow—while comparing it with related patterns and outlining its pros and cons.

macrozheng
macrozheng
macrozheng
Mastering the State Pattern: Theory, Java Examples, and Real‑World Order Workflow

What is the State Pattern?

The State Pattern (also called State Machine Pattern) allows an object to change its behavior when its internal state changes, making the object appear to have changed its class; behavior is bound to state.

Application Scenarios

When behavior must change with the object's state.

When an operation contains many branches that depend on the object's state.

Key Roles

Context (maintains a reference to the current state and delegates requests).

Abstract State (defines the interface for state‑specific behavior).

Concrete State (implements behavior for a specific state and handles state transitions).

Example: User Actions with Login State

An abstract

UserState

defines

forward()

,

collect()

, and

comment(String)

.

LoginState

and

UnLoginState

implement these methods;

UnLoginState

redirects to login before delegating.

AppContext

holds the current state and switches it.

<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(); appContext.forward(); }
    @Override public void collect() { forward2Login(); appContext.collect(); }
    @Override public void comment(String comment) { forward2Login(); appContext.comment(comment); }
    private void forward2Login() { System.out.println("跳转到登录页面!"); appContext.setState(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 UserState getState() { return this.currentState; }
    public void forward() { this.currentState.forward(); }
    public void collect() { this.currentState.collect(); }
    public void comment(String comment) { this.currentState.comment(comment); }
}

public class Test {
    public static void main(String[] args) {
        AppContext context = new AppContext();
        context.forward();
        context.collect();
        context.comment("说的太好了,双手双脚给个赞👍");
    }
}
</code>

State Machine for Order Workflow

Using Spring StateMachine to model order status transitions (WAIT_PAYMENT → WAIT_DELIVER → WAIT_RECEIVE → FINISH). The configuration defines states, events, transitions, and a persister. The service layer creates orders, sends events, and handles concurrency.

<code>@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);
    }
    @Bean
    public DefaultStateMachinePersister persister() {
        return new DefaultStateMachinePersister<>(new StateMachinePersist<Object, Object, Order>() {
            @Override public void write(StateMachineContext<Object, Object> context, Order order) {}
            @Override public StateMachineContext<Object, Object> read(Order order) {
                return new DefaultStateMachineContext(order.getStatus(), null, null, null);
            }
        });
    }
}

public interface IOrderService {
    Order create();
    Order pay(int id);
    Order deliver(int id);
    Order receive(int id);
    Map<Integer, Order> getOrders();
}

@Service("orderService")
public class OrderServiceImpl implements IOrderService {
    @Autowired private StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine;
    @Autowired private StateMachinePersister<OrderStatus, OrderStatusChangeEvent, Order> persister;
    private int id = 1;
    private Map<Integer, Order> orders = new HashMap<>();
    @Override public Order create() { Order o = new Order(); o.setStatus(OrderStatus.WAIT_PAYMENT); o.setId(id++); orders.put(o.getId(), o); return o; }
    @Override public Order pay(int id) { return handle(id, OrderStatusChangeEvent.PAYED); }
    @Override public Order deliver(int id) { return handle(id, OrderStatusChangeEvent.DELIVERY); }
    @Override public Order receive(int id) { return handle(id, OrderStatusChangeEvent.RECEIVED); }
    private Order handle(int id, OrderStatusChangeEvent event) {
        Order order = orders.get(id);
        Message<OrderStatusChangeEvent> msg = MessageBuilder.withPayload(event).setHeader("order", order).build();
        if (!sendEvent(msg, order)) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 操作失败, 状态异常,订单号:" + id);
        }
        return orders.get(id);
    }
    private synchronized boolean sendEvent(Message<OrderStatusChangeEvent> message, Order order) {
        boolean result = false;
        try {
            orderStateMachine.start();
            persister.restore(orderStateMachine, order);
            Thread.sleep(1000);
            result = orderStateMachine.sendEvent(message);
            persister.persist(orderStateMachine, order);
        } catch (Exception e) { e.printStackTrace(); }
        finally { orderStateMachine.stop(); }
        return result;
    }
    @Override public Map<Integer, Order> getOrders() { return orders; }
}
</code>

Related Patterns

The State Pattern shares similarities with the Chain of Responsibility (both reduce extensive if‑else chains) and the Strategy Pattern (similar UML structure), but differs in intent: State focuses on internal state transitions, while Chain of Responsibility manages external handler chains and Strategy selects interchangeable algorithms.

Advantages and Disadvantages

Clear structure: state classes replace bulky conditional logic, improving maintainability.

Explicit state transitions make behavior easier to understand.

State classes have well‑defined responsibilities and are extensible.

Drawbacks include class explosion for many states, increased complexity, and limited support for the Open/Closed principle when adding new states.

design-patternsJavaSoftware ArchitectureState PatternSpring StateMachine
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.