Skip to content

Commit f149945

Browse files
authored
Implement the Behavioral Design Patterns (#7)
* Implement the Chain of Responsibility Design Pattern * Implement the Command Design Pattern * Implement the Iterator Design Pattern * Implement the Mediator Design Pattern * Implement the Memento Design Pattern * Implement the Observer Design Pattern * Implement the State Design Pattern * Implement the Strategy Design Pattern * Implement the Template Method Design Pattern * Implement the Visitor Design Pattern
1 parent 3eb27d1 commit f149945

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1447
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package practice.behavioral.chain;
2+
3+
4+
import java.util.Arrays;
5+
import java.util.List;
6+
7+
/**
8+
* Example of Chain of Responsibility Design Pattern
9+
*/
10+
public final class ChainDemo {
11+
12+
public static void main(final String... arguments) {
13+
14+
getWorkList().forEach(makeWorkerChain()::perform);
15+
}
16+
17+
private static Worker makeWorkerChain() {
18+
19+
final var general = new General();
20+
general.setNext(new King());
21+
22+
final var jailer = new Jailer();
23+
jailer.setNext(general);
24+
25+
final var officer = new Officer();
26+
officer.setNext(jailer);
27+
28+
return officer;
29+
}
30+
31+
private static List<Work> getWorkList() {
32+
return Arrays.asList(
33+
new Work(WorkType.INTERROGATE, "interrogation"),
34+
new Work(WorkType.COLLECT_TAX, "tax-collection"),
35+
new Work(WorkType.SLAY_DRAGON, "dragon-slaying"),
36+
new Work(WorkType.PLAN_BATTLE, "castle-defense")
37+
);
38+
}
39+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package practice.behavioral.chain;
2+
3+
import lombok.NonNull;
4+
import lombok.RequiredArgsConstructor;
5+
import lombok.ToString;
6+
7+
@ToString
8+
@RequiredArgsConstructor
9+
public final class General extends Worker {
10+
11+
private static final int MAX_PRIORITY = 3;
12+
13+
@NonNull
14+
private final int capability; // Handling Limit
15+
16+
public General() {
17+
this(MAX_PRIORITY);
18+
}
19+
20+
@Override
21+
protected boolean canHandle(final @NonNull WorkType workType) {
22+
return workType.getLevel() <= capability; // Check Work TIER
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package practice.behavioral.chain;
2+
3+
import lombok.NonNull;
4+
import lombok.RequiredArgsConstructor;
5+
import lombok.ToString;
6+
7+
@ToString
8+
@RequiredArgsConstructor
9+
public final class Jailer extends Worker {
10+
11+
private static final int MAX_PRIORITY = 2;
12+
13+
@NonNull
14+
private final int capability; // Handling Limit
15+
16+
public Jailer() {
17+
this(MAX_PRIORITY);
18+
}
19+
20+
@Override
21+
protected boolean canHandle(final @NonNull WorkType workType) {
22+
return workType.getLevel() <= capability; // Check Work TIER
23+
}
24+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package practice.behavioral.chain;
2+
3+
import lombok.NonNull;
4+
import lombok.ToString;
5+
import lombok.extern.java.Log;
6+
7+
@Log
8+
@ToString
9+
public final class King extends Worker {
10+
11+
@Override
12+
protected boolean canHandle(final @NonNull WorkType workType) {
13+
return true; // LAST Worker should be ABLE to handle ANY Tier
14+
}
15+
16+
@Override
17+
public void perform(@NonNull final Work work) {
18+
var name = getClass().getSimpleName(); // Fetch Worker NAME
19+
var order = work.getDescription(); // Get ORDER Description
20+
log.info("Worker for <" + order + "> Job => " + name);
21+
}
22+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package practice.behavioral.chain;
2+
3+
import lombok.NonNull;
4+
import lombok.RequiredArgsConstructor;
5+
import lombok.ToString;
6+
7+
@ToString
8+
@RequiredArgsConstructor
9+
public final class Officer extends Worker {
10+
11+
private static final int MAX_PRIORITY = 1;
12+
13+
@NonNull
14+
private final int capability; // Handling Limit
15+
16+
public Officer() {
17+
this(MAX_PRIORITY);
18+
}
19+
20+
@Override
21+
protected boolean canHandle(final @NonNull WorkType workType) {
22+
return workType.getLevel() <= capability; // Check Work TIER
23+
}
24+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package practice.behavioral.chain;
2+
3+
import lombok.Data;
4+
import lombok.NonNull;
5+
6+
@Data
7+
public final class Work {
8+
9+
@NonNull
10+
private final WorkType workType;
11+
@NonNull
12+
private final String description;
13+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package practice.behavioral.chain;
2+
3+
import lombok.Getter;
4+
import lombok.NonNull;
5+
import lombok.RequiredArgsConstructor;
6+
import lombok.ToString;
7+
8+
@Getter
9+
@ToString
10+
@RequiredArgsConstructor
11+
public enum WorkType {
12+
13+
COLLECT_TAX(1),
14+
INTERROGATE(2),
15+
PLAN_BATTLE(3),
16+
SLAY_DRAGON(4);
17+
18+
@NonNull
19+
private final int level;
20+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package practice.behavioral.chain;
2+
3+
import lombok.NonNull;
4+
import lombok.Setter;
5+
import lombok.extern.java.Log;
6+
7+
@Log
8+
@Setter
9+
public abstract sealed class Worker permits General, Jailer, King, Officer {
10+
11+
protected Worker next; // Worker who is NEXT in CHAIN of Responsibility
12+
13+
protected abstract boolean canHandle(final @NonNull WorkType workType);
14+
15+
public void perform(@NonNull final Work work) {
16+
if (canHandle(work.getWorkType())) {
17+
var name = getClass().getSimpleName(); // Fetch Worker NAME
18+
var order = work.getDescription(); // Get ORDER Description
19+
log.info("Worker for <" + order + "> Job => " + name);
20+
} else {
21+
next.perform(work); // DELEGATE to Worker next up in CHAIN
22+
}
23+
}
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package practice.behavioral.command;
2+
3+
/**
4+
* Example of Command Design Pattern
5+
*/
6+
public final class CommandDemo {
7+
8+
public static void main(final String... arguments) {
9+
10+
final var gardenTask = new SwitchTask(new SwitchButton("Garden"));
11+
final var toiletTask = new SwitchTask(new SwitchButton("Toilet"));
12+
final var kitchenTask = new SwitchTask(new SwitchButton("Kitchen"));
13+
final var bedroomTask = new SwitchTask(new SwitchButton("Bedroom"));
14+
15+
final var remoteControl = new RemoteControl(); // Invoker of Switch Tasks
16+
17+
remoteControl.pressButton(gardenTask); // Turns ON Switch at the Garden
18+
remoteControl.pressButton(toiletTask); // Turns ON Switch at the Toilet
19+
remoteControl.pressButton(kitchenTask); // Turns ON Switch at the Kitchen
20+
remoteControl.pressButton(bedroomTask); // Turns ON Switch at the Bedroom
21+
22+
remoteControl.undoAction(); // UNDO Task = Turns OFF Switch at the Bedroom
23+
remoteControl.undoAction(); // UNDO Task = Turns OFF Switch at the Kitchen
24+
25+
remoteControl.redoAction(); // REDO Task = Turns ON Switch at the Kitchen
26+
remoteControl.redoAction(); // REDO Task = Turns ON Switch at the Bedroom
27+
}
28+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package practice.behavioral.command;
2+
3+
import java.util.Deque;
4+
import java.util.LinkedList;
5+
import lombok.EqualsAndHashCode;
6+
import lombok.NonNull;
7+
import lombok.ToString;
8+
import lombok.extern.java.Log;
9+
10+
@Log
11+
@ToString
12+
@EqualsAndHashCode
13+
public final class RemoteControl {
14+
15+
@NonNull
16+
private final Deque<SwitchTask> undoStack = new LinkedList<>();
17+
@NonNull
18+
private final Deque<SwitchTask> redoStack = new LinkedList<>();
19+
20+
public void pressButton(@NonNull final SwitchTask task) {
21+
log.info("Performing Task => [" + task + "]");
22+
task.execute(); // Toggle from CURRENT State
23+
undoStack.offerLast(task);
24+
}
25+
26+
public void undoAction() {
27+
if (undoStack.isEmpty()) {
28+
log.warning("No Action is available to UNDO!");
29+
return;
30+
}
31+
var lastAction = undoStack.pollLast();
32+
redoStack.offerLast(lastAction);
33+
log.info("UNDO of Action => [" + lastAction + "]");
34+
lastAction.execute(); // Toggle to LAST State
35+
}
36+
37+
public void redoAction() {
38+
if (redoStack.isEmpty()) {
39+
log.warning("No Action is available to REDO!");
40+
return;
41+
}
42+
var lastAction = redoStack.pollLast();
43+
undoStack.offerLast(lastAction);
44+
log.info("REDO of Action => [" + lastAction + "]");
45+
lastAction.execute(); // Toggle to LAST State
46+
}
47+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package practice.behavioral.command;
2+
3+
import lombok.EqualsAndHashCode;
4+
import lombok.NonNull;
5+
import lombok.RequiredArgsConstructor;
6+
import lombok.ToString;
7+
import lombok.extern.java.Log;
8+
9+
@Log
10+
@ToString
11+
@EqualsAndHashCode
12+
@RequiredArgsConstructor
13+
public final class SwitchButton {
14+
15+
@NonNull
16+
private final String location;
17+
private boolean state = false;
18+
19+
public void toggleState() {
20+
state = !state;
21+
}
22+
23+
public void printState() {
24+
var isOn = state ? "ON" : "OFF"; // Determine current state of Switch
25+
log.info("State of <" + location + "> Switch => [" + isOn + "]");
26+
}
27+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package practice.behavioral.command;
2+
3+
import lombok.EqualsAndHashCode;
4+
import lombok.NonNull;
5+
import lombok.RequiredArgsConstructor;
6+
import lombok.ToString;
7+
8+
@ToString
9+
@EqualsAndHashCode
10+
@RequiredArgsConstructor
11+
public final class SwitchTask {
12+
13+
@NonNull
14+
private final SwitchButton switcher;
15+
16+
public void execute() {
17+
switcher.toggleState();
18+
switcher.printState();
19+
}
20+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package practice.behavioral.iterator;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import lombok.EqualsAndHashCode;
6+
import lombok.NonNull;
7+
import lombok.RequiredArgsConstructor;
8+
import lombok.ToString;
9+
import lombok.extern.java.Log;
10+
11+
@Log
12+
@ToString
13+
@EqualsAndHashCode
14+
@RequiredArgsConstructor
15+
public final class Attic {
16+
17+
@NonNull
18+
private final List<Item> items;
19+
20+
public void takeItems(@NonNull final ItemType itemType) {
21+
final var robber = new Robber(itemType, new ArrayList<>(items));
22+
log.info("Searching for Item Type => [" + itemType + "]");
23+
// log.info("ALL Items => " + getItems()); // Print ALL Items
24+
while (robber.hasNextItem()) {
25+
log.info("Item in Attic => [" + robber.nextItem() + "]");
26+
}
27+
}
28+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package practice.behavioral.iterator;
2+
3+
import lombok.Data;
4+
import lombok.NonNull;
5+
6+
@Data
7+
public final class Item {
8+
9+
@NonNull
10+
private final ItemType itemType;
11+
@NonNull
12+
private final String description;
13+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package practice.behavioral.iterator;
2+
3+
import lombok.NonNull;
4+
import lombok.RequiredArgsConstructor;
5+
import lombok.ToString;
6+
7+
@ToString
8+
@RequiredArgsConstructor
9+
public enum ItemType {
10+
11+
ANTIC(1),
12+
SWORD(2),
13+
ARMOR(3),
14+
CROWN(4);
15+
16+
@NonNull
17+
private final int tier;
18+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package practice.behavioral.iterator;
2+
3+
public sealed interface Iterator<T> permits Robber {
4+
5+
boolean hasNextItem(); // Check availability
6+
7+
T nextItem(); // Get NEXT Item by some logic
8+
}

0 commit comments

Comments
 (0)