January 25, 2021
Hot Topics:

Working With Design Patterns: State

  • By Jeff Langr
  • Send Email »
  • More Articles »

The Holding class that remains (see Listing 6) is now devoid of most conditional logic! I can now test it, too, with excruciating ease.

The state pattern is one of the few design patterns that requires tight coupling between its classes: The Holding class is dependent upon the initial state, and each of the states is in turn dependent upon Holding. Although there are some clever ways to break this, it's probably not necessary, because the classes represent a self-enclosed subsystem that can remain isolated from the rest of the system. For the implementation of the state classes, I took advantage of Java's package-level access, directly having the states access Holding variables as needed, but not exposing these fields to external clients of Holding. It's one of the rare cases where I won't insist that a field remain private.

Listing 6: Holding, using the state design pattern.

import java.util.*;

public class Holding {
   private final Book book;
   private final int copyNumber;

   Date checkoutDate;
   String holdPatron;
   Date holdDate;
   HoldingState state = new CheckedIn(this);
   Date checkinDate;

   public Holding(Book book, int copyNumber) {
      this.book = book;
      this.copyNumber = copyNumber;

   public Book getBook() {
      return book;

   public int getCopyNumber() {
      return copyNumber;

   public boolean isOnLoan() {
      return checkoutDate != null;

   public Date getLoanDate() {
      return checkoutDate;

   public void checkout(Date date, String patronId) {
      state.checkout(date, patronId);

   public void checkin(Date date) {

   public void placeHold(Date date, String patronId) {
      state.placeHold(date, patronId);

   public void update(Date date) {

   public boolean isOnHold() {
      return holdPatron != null;

   public void releaseAnyHold() {
      holdPatron = null;

   // callback actions
   void doHold(Date date, String patronId) {
      holdPatron = patronId;
      holdDate = date;

   void doCheckout(Date date, String patronId) {
      checkoutDate = date;

   public void doCheckin(Date date) {
      checkoutDate = null;

   public void doReleaseOldHold(Date updatedAt) {
      if (DateUtil.daysBetween(holdDate, updatedAt) >= 3)

Adding new functionality into the state diagram usually is simple and straightforward. The separate state classes help keep conditional logic to a minimum by avoiding confusion about the conditions under which something can occur. Often, modifications will necessitate changes to transitions between states, requiring updates to multiple state derivatives. Drawing a state diagram can be a good idea, but there's another possible solution to help manage the transitions.

State diagrams can be represented as simple tables. If I were to refactor to a more disciplined implementation of the state pattern, I could dramatically simplify my work. The table would define event methods and callback action method names; these would be used to automatically generate code for the state derivatives. This automation can be critical in a highly dynamic state system. The Object Mentor web site contains a download for just such a Java code generator, SMC (State Machine Compiler). There also are state pattern variants that can simplify state system changes in a more dynamic subsystem.

Click here for a larger image.

Figure 2: The State pattern.

About the Author

Jeff Langr is a veteran software developer with over a quarter century of professional software development experience. He's written two books, including Agile Java: Crafting Code With Test-Driven Development (Prentice Hall) in 2005. Jeff has contributed a couple chapters to Uncle Bob Martin's upcoming book, Clean Code. Jeff has written over 75 articles on software development, with over thirty appearing at Developer.com. You can find out more about Jeff at his site, http://langrsoft.com, or you can contact him via email at jeff at langrsoft dot com.

Page 4 of 4

This article was originally published on June 19, 2008

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date