June 19, 2018
Hot Topics:

Working With Design Patterns: State

  • June 19, 2008
  • By Jeff Langr
  • Send Email »
  • More Articles »

Conditional logic is essential to building any application, yet too much can make an application incomprehensible. Many of the applications I build require that an object exist in many different states, with behavior differing from state to state. A straightforward implementation involves lots of if statements and complex conditionals, producing overly convoluted solutions in short order. As a remedy, I use the state design pattern to keep my code from getting out of hand.

Holdings in a library provide a good example. A holding is a copy of a book (see Listing 1). (In my implementation, the book is simply the ISBN classification information. Thus, each holding object references a copy number and a book object.) Holdings can be checked out, checked in, they can be moved from branch to branch, they can be held by a patron, they can be warehoused, and so on. Each of these events puts the holding into a state where different rules apply. For example, a book that's checked out obviously can't be warehoused.

Listing 1: The Book class.

// BookTest.java
import static org.junit.Assert.*;
import org.junit.*;

public class BookTest {
   public static final Book CATCH22 = new Book("0-671-12805-1",
      "Catch-22", "Heller, Joseph", "1961");

   public void create() {
      assertEquals("0-671-12805-1", CATCH22.getIsbn());
      assertEquals("Catch-22", CATCH22.getTitle());
      assertEquals("Heller, Joseph", CATCH22.getAuthor());
      assertEquals("1961", CATCH22.getYear());

// Book.java
public class Book {
   private final String isbn;
   private final String title;
   private final String author;
   private final String year;

   public Book(String isbn, String title, String author,
      String year) {
      this.isbn = isbn;
      this.title = title;
      this.author = author;
      this.year = year;

   public String getIsbn() {
      return isbn;

   public String getTitle() {
      return title;

   public String getAuthor() {
      return author;

   public String getYear() {
      return year;

Listing 2 shows a starter implementation for Holding. (Note that I'm not yet concerned with the relevancy of the patron ID.)

Listing 2: An initial Holding implementation.

import static org.junit.Assert.*;
import java.util.Date;
import org.junit.*;

public class HoldingTest {
   private Holding holding;
   private static final Date NOW = new Date();
   private static final String PATRON_ID = "12345";

   public void initialize() {
      Book book = BookTest.CATCH22;
      int copyNumber = 1;
      holding = new Holding(book, copyNumber);

   public void create() {
      assertSame(BookTest.CATCH22, holding.getBook());
      assertEquals(1, holding.getCopyNumber());

   public void checkout() {
      holding.checkout(NOW, PATRON_ID);
      assertEquals(NOW, holding.getLoanDate());

   public void checkin() {
      Date later = new Date(NOW.getTime() + 1);
      holding.checkout(NOW, PATRON_ID);

// Holding.java
import java.util.Date;

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

   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) {
      checkoutDate = date;

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

Page 1 of 4

Comment and Contribute


(Maximum characters: 1200). You have characters left.



Enterprise Development Update

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

By submitting your information, you agree that developer.com may send you developer offers via email, phone and text message, as well as email offers about other products and services that developer believes may be of interest to you. developer will process your information in accordance with the Quinstreet Privacy Policy.


We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.
Thanks for your registration, follow us on our social networks to keep up-to-date