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;
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;
}
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();
}
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);
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