diff --git a/DesignPatterns/README.md b/DesignPatterns/README.md index 4e13b79..c19efc4 100644 --- a/DesignPatterns/README.md +++ b/DesignPatterns/README.md @@ -8,6 +8,7 @@ This project explores various design patterns and their implementations in moder ### Behavioral Design Patterns 💪 +- [Command](src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command) 📝 - [Strategy](src/main/java/pl/mperor/lab/java/design/pattern/behavioral/strategy) 🎯 - [Execute Around Method (EAM)](src/main/java/pl/mperor/lab/java/design/pattern/behavioral/eam) ⭕ diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/Account.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/Account.java new file mode 100644 index 0000000..d6c2d0b --- /dev/null +++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/Account.java @@ -0,0 +1,27 @@ +package pl.mperor.lab.java.design.pattern.behavioral.command; + +class Account { + + private double balance; + private boolean active; + + void deposit(double amount) { + balance += amount; + } + + void withdraw(double amount) { + balance -= amount; + } + + void changeActive() { + active = !active; + } + + double getBalance() { + return balance; + } + + boolean isActive() { + return active; + } +} diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/AccountDepositCommand.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/AccountDepositCommand.java new file mode 100644 index 0000000..0222f9e --- /dev/null +++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/AccountDepositCommand.java @@ -0,0 +1,14 @@ +package pl.mperor.lab.java.design.pattern.behavioral.command; + +record AccountDepositCommand(Account account, double deposit) implements Command { + + @Override + public void execute() { + account.deposit(deposit); + } + + @Override + public Command reversed() { + return new AccountWithdrawCommand(account, deposit); + } +} diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/AccountWithdrawCommand.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/AccountWithdrawCommand.java new file mode 100644 index 0000000..cd13ace --- /dev/null +++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/AccountWithdrawCommand.java @@ -0,0 +1,14 @@ +package pl.mperor.lab.java.design.pattern.behavioral.command; + +record AccountWithdrawCommand(Account account, double withdraw) implements Command { + + @Override + public void execute() { + account.withdraw(withdraw); + } + + @Override + public Command reversed() { + return new AccountDepositCommand(account, withdraw); + } +} diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/Command.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/Command.java new file mode 100644 index 0000000..b42030e --- /dev/null +++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/Command.java @@ -0,0 +1,11 @@ +package pl.mperor.lab.java.design.pattern.behavioral.command; + +@FunctionalInterface +public interface Command { + + void execute(); + + default Command reversed() { + return this; + } +} diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/CommandRegister.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/CommandRegister.java new file mode 100644 index 0000000..b138784 --- /dev/null +++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/command/CommandRegister.java @@ -0,0 +1,32 @@ +package pl.mperor.lab.java.design.pattern.behavioral.command; + +import java.util.Deque; +import java.util.LinkedList; + +class CommandRegister { + + private final Deque historyCommands = new LinkedList<>(); + private final Deque redoCommands = new LinkedList<>(); + + void execute(Command command) { + command.execute(); + historyCommands.push(command); + redoCommands.clear(); + } + + void undo() { + if (!historyCommands.isEmpty()) { + var command = historyCommands.pop(); + redoCommands.push(command); + command.reversed().execute(); + } + } + + void redo() { + if (!redoCommands.isEmpty()) { + var command = redoCommands.pop(); + historyCommands.push(command); + command.execute(); + } + } +} diff --git a/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/command/CommandRegistryTest.java b/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/command/CommandRegistryTest.java new file mode 100644 index 0000000..632eb90 --- /dev/null +++ b/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/command/CommandRegistryTest.java @@ -0,0 +1,51 @@ +package pl.mperor.lab.java.design.pattern.behavioral.command; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class CommandRegistryTest { + + @Test + public void testUndoRedoImplementationWithCommandPattern() { + Account account = new Account(); + CommandRegister commander = new CommandRegister(); + commander.execute(account::changeActive); + commander.execute(new AccountDepositCommand(account, 10)); + Assert.that(account).active(true).balance(10); + + commander.undo(); + Assert.that(account).active(true).balance(0); + + commander.undo(); + Assert.that(account).active(false).balance(0); + + commander.redo(); + Assert.that(account).active(true).balance(0); + + commander.redo(); + Assert.that(account).active(true).balance(10); + } + + static class Assert { + + private Account account; + + Assert(Account account) { + this.account = account; + } + + Assert active(boolean active) { + Assertions.assertEquals(active, account.isActive()); + return this; + } + + Assert balance(double balance) { + Assertions.assertEquals(balance, account.getBalance()); + return this; + } + + static Assert that(Account account) { + return new Assert(account); + } + } +} \ No newline at end of file