Skip to content

Commit 4ceb0c7

Browse files
authored
Add command design pattern with test case (#51)
1 parent de02911 commit 4ceb0c7

File tree

7 files changed

+150
-0
lines changed

7 files changed

+150
-0
lines changed

DesignPatterns/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This project explores various design patterns and their implementations in moder
88

99
### Behavioral Design Patterns 💪
1010

11+
- [Command](src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command) 📝
1112
- [Strategy](src/main/java/pl/mperor/lab/java/design/pattern/behavioral/strategy) 🎯
1213
- [Execute Around Method (EAM)](src/main/java/pl/mperor/lab/java/design/pattern/behavioral/eam)
1314

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package pl.mperor.lab.java.design.pattern.behavioral.command;
2+
3+
class Account {
4+
5+
private double balance;
6+
private boolean active;
7+
8+
void deposit(double amount) {
9+
balance += amount;
10+
}
11+
12+
void withdraw(double amount) {
13+
balance -= amount;
14+
}
15+
16+
void changeActive() {
17+
active = !active;
18+
}
19+
20+
double getBalance() {
21+
return balance;
22+
}
23+
24+
boolean isActive() {
25+
return active;
26+
}
27+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package pl.mperor.lab.java.design.pattern.behavioral.command;
2+
3+
record AccountDepositCommand(Account account, double deposit) implements Command {
4+
5+
@Override
6+
public void execute() {
7+
account.deposit(deposit);
8+
}
9+
10+
@Override
11+
public Command reversed() {
12+
return new AccountWithdrawCommand(account, deposit);
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package pl.mperor.lab.java.design.pattern.behavioral.command;
2+
3+
record AccountWithdrawCommand(Account account, double withdraw) implements Command {
4+
5+
@Override
6+
public void execute() {
7+
account.withdraw(withdraw);
8+
}
9+
10+
@Override
11+
public Command reversed() {
12+
return new AccountDepositCommand(account, withdraw);
13+
}
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package pl.mperor.lab.java.design.pattern.behavioral.command;
2+
3+
@FunctionalInterface
4+
public interface Command {
5+
6+
void execute();
7+
8+
default Command reversed() {
9+
return this;
10+
}
11+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package pl.mperor.lab.java.design.pattern.behavioral.command;
2+
3+
import java.util.Deque;
4+
import java.util.LinkedList;
5+
6+
class CommandRegister {
7+
8+
private final Deque<Command> historyCommands = new LinkedList<>();
9+
private final Deque<Command> redoCommands = new LinkedList<>();
10+
11+
void execute(Command command) {
12+
command.execute();
13+
historyCommands.push(command);
14+
redoCommands.clear();
15+
}
16+
17+
void undo() {
18+
if (!historyCommands.isEmpty()) {
19+
var command = historyCommands.pop();
20+
redoCommands.push(command);
21+
command.reversed().execute();
22+
}
23+
}
24+
25+
void redo() {
26+
if (!redoCommands.isEmpty()) {
27+
var command = redoCommands.pop();
28+
historyCommands.push(command);
29+
command.execute();
30+
}
31+
}
32+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package pl.mperor.lab.java.design.pattern.behavioral.command;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.Test;
5+
6+
public class CommandRegistryTest {
7+
8+
@Test
9+
public void testUndoRedoImplementationWithCommandPattern() {
10+
Account account = new Account();
11+
CommandRegister commander = new CommandRegister();
12+
commander.execute(account::changeActive);
13+
commander.execute(new AccountDepositCommand(account, 10));
14+
Assert.that(account).active(true).balance(10);
15+
16+
commander.undo();
17+
Assert.that(account).active(true).balance(0);
18+
19+
commander.undo();
20+
Assert.that(account).active(false).balance(0);
21+
22+
commander.redo();
23+
Assert.that(account).active(true).balance(0);
24+
25+
commander.redo();
26+
Assert.that(account).active(true).balance(10);
27+
}
28+
29+
static class Assert {
30+
31+
private Account account;
32+
33+
Assert(Account account) {
34+
this.account = account;
35+
}
36+
37+
Assert active(boolean active) {
38+
Assertions.assertEquals(active, account.isActive());
39+
return this;
40+
}
41+
42+
Assert balance(double balance) {
43+
Assertions.assertEquals(balance, account.getBalance());
44+
return this;
45+
}
46+
47+
static Assert that(Account account) {
48+
return new Assert(account);
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)