Balking Pattern Java

Intent

A balking Pattern is used to prevent an object from executing certain codes if it is an incomplete or inappropriate state.

Wikipedia Says

The balking pattern is a software design pattern that only executes an action on an object when the object is in a particular state. For example, if an object reads ZIPfiles and a calling method invokes a get method on the object when the ZIP file is not open, the object would "balk" at the request. In the Java programming language, for example, an IllegalStateException might be thrown under these circumstances.

Source code

In this example implementation, WashingMachine is an object that has two states in which it can be: ENABLED and WASHING. If the machine is ENABLED the state is changed into WASHING that any other thread can't invoke this action on this and then do the job. On the other hand, if it has been already washing and any other thread execute wash() it can't do that once again and returns doing nothing.

Class Diagram


Step 1: Create a Washing machine class.
package com.iluwatar.balking;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Washing machine class
 */
public class WashingMachine {

  private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class);

  private WashingMachineState washingMachineState;

  public WashingMachine() {
    washingMachineState = WashingMachineState.ENABLED;
  }

  public WashingMachineState getWashingMachineState() {
    return washingMachineState;
  }

  /**
   * Method responsible for washing
   * if the object is in appropriate state
   */
  public void wash() {
    synchronized (this) {
      LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), getWashingMachineState());
      if (washingMachineState == WashingMachineState.WASHING) {
        LOGGER.error("ERROR: Cannot wash if the machine has been already washing!");
        return;
      }
      washingMachineState = WashingMachineState.WASHING;
    }
    LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
    try {
      Thread.sleep(50);
    } catch (InterruptedException ie) {
      ie.printStackTrace();
    }
    endOfWashing();
  }

  /**
   * Method responsible of ending the washing
   * by changing machine state
   */
  public synchronized void endOfWashing() {
    washingMachineState = WashingMachineState.ENABLED;
    LOGGER.info("{}: Washing completed.", Thread.currentThread().getId());
  }

}
Step 2: Create WashingMachineState enum describes in which state machine is, it can be enabled and ready to work as well as during washing.
package com.iluwatar.balking;

public enum WashingMachineState {
  ENABLED, WASHING
}
 Step 3: Let's test this design pattern.
public class BalkingPatternDemo {

  private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

  /**
   * @param args the command line arguments - not used
   */
  public static void main(String... args) {
    final WashingMachine washingMachine = new WashingMachine();
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 3; i++) {
      executorService.execute(washingMachine::wash);
    }
    executorService.shutdown();
    try {
      executorService.awaitTermination(10, TimeUnit.SECONDS);
    } catch (InterruptedException ie) {
      LOGGER.error("ERROR: Waiting on executor service shutdown!");
    }
  }

}

Applicability

Use the Balking pattern when
  • you want to invoke an action on an object only when it is in a particular state
  • objects are generally only in a state that is prone to balking temporarily but for an unknown amount of time.

Related patterns


Comments