CodePark/ questions / Behavioral patterns
START PRACTICINGPRACTICE
Backend question · Software design & patterns › Behavioral patterns

An Order has statuses draft, placed, paid, shipped and cancelled, and methods like pay(), ship() and cancel() full of if (status === ...) checks. How would the State pattern help, and when is a simpler approach enough?

The State pattern moves the behaviour that depends on status into one object per state. Order holds a state object. order.pay() hands the work to this.state.pay(order).

For example:

  • PlacedState.pay() records the payment and switches the order to PaidState.
  • ShippedState.cancel() throws an invalid transition error.

Each state class lists exactly what is allowed from that state. To add a state, you add a class. You don't edit the conditionals in every method.

It is worth it when many operations behave differently per state and the rules are complex. Sometimes the logic is mostly "is this transition allowed?". Then a simpler option is an explicit transition table. For example, a map from each status to its allowed next statuses, checked in one transitionTo() method. This keeps the order a plain object that is easy to save to the database. It also puts the rules in one readable place.

Either way, keep transitions inside the aggregate (the Order domain object). Don't let services set status directly.

  • There is one class per state, and the context passes each call to the current state.
  • Each state defines its allowed operations and its next state.
  • The pattern is worth it when many operations change by state.
  • A transition table is often enough for simple allowed-transition rules.
  • Keep transitions inside the domain object.