Skip to content

Instantly share code, notes, and snippets.

@exallium
Last active August 29, 2015 14:27
Show Gist options
  • Select an option

  • Save exallium/cb9abf99de69d365b87f to your computer and use it in GitHub Desktop.

Select an option

Save exallium/cb9abf99de69d365b87f to your computer and use it in GitHub Desktop.
UndoCommand Pattern
public enum Action {
ACTION1, ACTION2
}
/**
* Undoable command. T is a status of some sort.
* A command should know everything it needs to to perform an execute or an undo.
*/
public interface Command<T> {
T execute();
T undo();
}
public class Command1 implements Command<Boolean> {
@Override
Boolean execute() {
System.out.println("Ex Comm 1");
return true;
}
@Override
Boolean undo() {
System.out.println("Undo Comm 1");
return false;
}
}
public class Command2 implements Command<Boolean> {
@Override
Boolean execute() {
System.out.println("Ex Comm 2");
return true;
}
@Override
Boolean undo() {
System.out.println("Undo Comm 2");
return false;
}
}
/**
* Builds Commands given a subset of actions from an enum.
*/
public interface CommandFactory<T, E extends Enum<E>> {
Command<T> createCommand(E action);
}
public class CommandFactory<Boolean, Actions> {
@Override
Command<T> createCommand(E action) {
switch (action) {
case ACTION1:
return new Command1();
case ACTION2:
return new Command2();
}
}
}
/**
* An Invoker controls a stream of commands.
* execute will perform a new action
* undo will undo the most recent action
*/
public interface Invoker<T, E extends Enum<E>> {
T execute(@NotNull E action);
@Nullable
T undo();
}
public class Main {
public static void main(String [] args) {
// You could also inject Invoker via a DI framework ;)
// You can keep different invokers separate via a naming scheme.
final CommandFactory factory = new ExampleFactory();
final Invoker invoker = new SimpleInvoker(commandFactory);
invoker.execute(Action.ACTION1);
invoker.execute(Action.ACTION2);
invoker.undo();
invoker.undo();
}
}
/**
* This is the default invoker implementation
*/
public class SimpleInvoker<T, E extends Enum<E>> implements Invoker<T, E> {
private final Stack<Command<T>> stack = new Stack<>();
private final CommandFactory<T, E> commandFactory;
public SimpleInvoker(CommandFactory<T, E> commandFactory) {
this.commandFactory = commandFactory;
}
@Override
public T execute(@NotNull final E action) {
stack.push(commandFactory.createCommand(action));
return action.execute();
}
@Override
@Nullable
public T undo() {
return stack.isEmpty() ? null : stack.pop().undo();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment