|
9 | 9 | ---
|
10 | 10 |
|
11 | 11 | ## Intent
|
12 |
| -Balking Pattern is used to prevent an object from executing certain code if it is an |
13 |
| -incomplete or inappropriate state |
| 12 | + |
| 13 | +Balking Pattern is used to prevent an object from executing a certain code if it is in an incomplete |
| 14 | +or inappropriate state. |
| 15 | + |
| 16 | +## Explanation |
| 17 | + |
| 18 | +Real world example |
| 19 | + |
| 20 | +> There's a start-button in a washing machine to initiate the laundry washing. When the washing |
| 21 | +> machine is inactive the button works as expected, but if it's already washing the button does |
| 22 | +> nothing. |
| 23 | +
|
| 24 | +In plain words |
| 25 | + |
| 26 | +> Using the balking pattern, a certain code executes only if the object is in particular state. |
| 27 | +
|
| 28 | +Wikipedia says |
| 29 | + |
| 30 | +> The balking pattern is a software design pattern that only executes an action on an object when |
| 31 | +> the object is in a particular state. For example, if an object reads ZIP files and a calling |
| 32 | +> method invokes a get method on the object when the ZIP file is not open, the object would "balk" |
| 33 | +> at the request. |
| 34 | +
|
| 35 | +**Programmatic Example** |
| 36 | + |
| 37 | +In this example implementation, `WashingMachine` is an object that has two states in which it can |
| 38 | +be: ENABLED and WASHING. If the machine is ENABLED, the state changes to WASHING using a thread-safe |
| 39 | +method. On the other hand, if it already has been washing and any other thread executes `wash()` |
| 40 | +it won't do that and returns without doing anything. |
| 41 | + |
| 42 | +Here are the relevant parts of the `WashingMachine` class. |
| 43 | + |
| 44 | +```java |
| 45 | +@Slf4j |
| 46 | +public class WashingMachine { |
| 47 | + |
| 48 | + private final DelayProvider delayProvider; |
| 49 | + private WashingMachineState washingMachineState; |
| 50 | + |
| 51 | + public WashingMachine(DelayProvider delayProvider) { |
| 52 | + this.delayProvider = delayProvider; |
| 53 | + this.washingMachineState = WashingMachineState.ENABLED; |
| 54 | + } |
| 55 | + |
| 56 | + public WashingMachineState getWashingMachineState() { |
| 57 | + return washingMachineState; |
| 58 | + } |
| 59 | + |
| 60 | + public void wash() { |
| 61 | + synchronized (this) { |
| 62 | + var machineState = getWashingMachineState(); |
| 63 | + LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState); |
| 64 | + if (this.washingMachineState == WashingMachineState.WASHING) { |
| 65 | + LOGGER.error("Cannot wash if the machine has been already washing!"); |
| 66 | + return; |
| 67 | + } |
| 68 | + this.washingMachineState = WashingMachineState.WASHING; |
| 69 | + } |
| 70 | + LOGGER.info("{}: Doing the washing", Thread.currentThread().getName()); |
| 71 | + this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing); |
| 72 | + } |
| 73 | + |
| 74 | + public synchronized void endOfWashing() { |
| 75 | + washingMachineState = WashingMachineState.ENABLED; |
| 76 | + LOGGER.info("{}: Washing completed.", Thread.currentThread().getId()); |
| 77 | + } |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +Here's the simple `DelayProvider` interface used by the `WashingMachine`. |
| 82 | + |
| 83 | +```java |
| 84 | +public interface DelayProvider { |
| 85 | + void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task); |
| 86 | +} |
| 87 | +``` |
| 88 | + |
| 89 | +Now we introduce the application using the `WashingMachine`. |
| 90 | + |
| 91 | +```java |
| 92 | + public static void main(String... args) { |
| 93 | + final var washingMachine = new WashingMachine(); |
| 94 | + var executorService = Executors.newFixedThreadPool(3); |
| 95 | + for (int i = 0; i < 3; i++) { |
| 96 | + executorService.execute(washingMachine::wash); |
| 97 | + } |
| 98 | + executorService.shutdown(); |
| 99 | + try { |
| 100 | + executorService.awaitTermination(10, TimeUnit.SECONDS); |
| 101 | + } catch (InterruptedException ie) { |
| 102 | + LOGGER.error("ERROR: Waiting on executor service shutdown!"); |
| 103 | + Thread.currentThread().interrupt(); |
| 104 | + } |
| 105 | + } |
| 106 | +``` |
| 107 | + |
| 108 | +Here is the console output of the program. |
| 109 | + |
| 110 | +``` |
| 111 | +14:02:52.268 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Actual machine state: ENABLED |
| 112 | +14:02:52.272 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Doing the washing |
| 113 | +14:02:52.272 [pool-1-thread-3] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-3: Actual machine state: WASHING |
| 114 | +14:02:52.273 [pool-1-thread-3] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing! |
| 115 | +14:02:52.273 [pool-1-thread-1] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-1: Actual machine state: WASHING |
| 116 | +14:02:52.273 [pool-1-thread-1] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing! |
| 117 | +14:02:52.324 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - 14: Washing completed. |
| 118 | +``` |
14 | 119 |
|
15 | 120 | ## Class diagram
|
| 121 | + |
16 | 122 | 
|
17 | 123 |
|
18 | 124 | ## Applicability
|
| 125 | + |
19 | 126 | Use the Balking pattern when
|
20 | 127 |
|
21 |
| -* you want to invoke an action on an object only when it is in a particular state |
22 |
| -* objects are generally only in a state that is prone to balking temporarily |
23 |
| -but for an unknown amount of time |
| 128 | +* You want to invoke an action on an object only when it is in a particular state |
| 129 | +* Objects are generally only in a state that is prone to balking temporarily but for an unknown |
| 130 | + amount of time |
24 | 131 |
|
25 | 132 | ## Related patterns
|
26 |
| -* Guarded Suspension Pattern |
27 |
| -* Double Checked Locking Pattern |
| 133 | + |
| 134 | +* [Guarded Suspension Pattern](https://java-design-patterns.com/patterns/guarded-suspension/) |
| 135 | +* [Double Checked Locking Pattern](https://java-design-patterns.com/patterns/double-checked-locking/) |
| 136 | + |
| 137 | +## Credits |
| 138 | + |
| 139 | +* [Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML, 2nd Edition, Volume 1](https://www.amazon.com/gp/product/0471227293/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0471227293&linkId=0e39a59ffaab93fb476036fecb637b99) |
0 commit comments