public enum Size {
SMALL("small"), NORMAL("normal");
private String title;
Size(String title) { this.title = title; }
@Override public String toString() { return title; } }
public enum Visibility {
VISIBLE("visible"), INVISIBLE("invisible");
private String title;
Visibility(String title) { this.title = title; }
@Override public String toString() { return title; } }
public abstract class Command {
public abstract void execute(Target target);
public abstract void undo();
public abstract void redo();
@Override public abstract String toString();
}
public class ShrinkSpell extends Command {
private Size oldSize; private Target target;
@Override public void execute(Target target) { oldSize = target.getSize(); target.setSize(Size.SMALL); this.target = target; }
@Override public void undo() { if (oldSize != null && target != null) { var temp = target.getSize(); target.setSize(oldSize); oldSize = temp; } }
@Override public void redo() { undo(); }
@Override public String toString() { return "Shrink spell"; } }
public class InvisibilitySpell extends Command {
private Target target;
@Override public void execute(Target target) { target.setVisibility(Visibility.INVISIBLE); this.target = target; }
@Override public void undo() { if (target != null) { target.setVisibility(Visibility.VISIBLE); } }
@Override public void redo() { if (target != null) { target.setVisibility(Visibility.INVISIBLE); } }
@Override public String toString() { return "Invisibility spell"; } }
public abstract class Target {
private static final Logger LOGGER = LoggerFactory.getLogger(Target.class);
private Size size;
private Visibility visibility;
public Size getSize() { return size; }
public void setSize(Size size) { this.size = size; }
public Visibility getVisibility() { return visibility; }
public void setVisibility(Visibility visibility) { this.visibility = visibility; }
@Override public abstract String toString();
public void printStatus() { LOGGER.info("{}, [size={}] [visibility={}]", this, getSize(), getVisibility()); } }
public class Goblin extends Target {
public Goblin() { setSize(Size.NORMAL); setVisibility(Visibility.VISIBLE); }
@Override public String toString() { return "Goblin"; }
}
public class Wizard {
private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
private Deque<Command> undoStack = new LinkedList<>(); private Deque<Command> redoStack = new LinkedList<>();
public Wizard() { }
public void castSpell(Command command, Target target) { LOGGER.info("{} casts {} at {}", this, command, target); command.execute(target); undoStack.offerLast(command); }
public void undoLastSpell() { if (!undoStack.isEmpty()) { var previousSpell = undoStack.pollLast(); redoStack.offerLast(previousSpell); LOGGER.info("{} undoes {}", this, previousSpell); previousSpell.undo(); } }
public void redoLastSpell() { if (!redoStack.isEmpty()) { var previousSpell = redoStack.pollLast(); undoStack.offerLast(previousSpell); LOGGER.info("{} redoes {}", this, previousSpell); previousSpell.redo(); } }
@Override public String toString() { return "Wizard"; } }
public class App {
public static void main(String[] args) { var wizard = new Wizard(); var goblin = new Goblin();
goblin.printStatus();
wizard.castSpell(new ShrinkSpell(), goblin); goblin.printStatus();
wizard.castSpell(new InvisibilitySpell(), goblin); goblin.printStatus();
wizard.undoLastSpell(); goblin.printStatus();
wizard.undoLastSpell(); goblin.printStatus();
wizard.redoLastSpell(); goblin.printStatus();
wizard.redoLastSpell(); goblin.printStatus(); } }
|