This repository is an attempt to implement the undo-redo feature
introduced at Design Patters: Elements of Reusable Object-Oriented
Software1 book (page 62/358).
Basically, the book give us a problem to be solved by the following though:
The user is facing a program's state. It can go back to previous
states and also go to next states (since the undo store the states
which can be reaplied).
My solution approach is a stack based object: (suitable for
LIFO2 problems).
Now, we can:
- insert incoming objects (states) in our
undostack, - get the current state with
peek(undotop state = current state), - send top state from
undotoredostack whenever we call the undo action, - send top element from
redotoundostack whenever we call the redo action, - clear
redostack whenever a new states comes in our "UndoRedo" machine.
To clone the project you can:
# clone using git
git clone https://github.com/nasccped/DP-undo-redo-example
# remove git folder (works for bash based terminals, only)
rm -rf DP-undo-redo-example/.git/
# goto dir
cd DP-undo-redo-exampleSince this project was built under the kojamp3 project manager, you can use it to handle the project, or:
- compile using a bash terminal (Linux):
javac $(find src -type f -name **.java) -d out- compile using a powershell terminal (Windows):
javac (Get-ChildItem -Recurse -Path src -Filter *.java | ForEach-Object { $_.FullName }) -d outFinally, you can execute the program by running:
java --class-path out UndoRedoExampleOn the Design Patterns1 book, this kind of problem is used to exemplify the Lexi's4 program building.
The author enforces that our program must be able to execute (and
"unexecute") some actions. Command is a great design pattern to
this job!
However, I just want to provide this thinking technology of "goNext/goPrevious" in a machine state timeline (shown in image 1).
Our app can be separated into three pieces:
- user input catching+parsing
- the machine itself
- utilities used throughout the code
Before defining the valid user input values, we should think about how our machine works.
The machine doesn't work with real states and commands, but it should
store values as states and run actions. They both come from the user
input's default type (String).
With this in mind, we should be able to turn Strings into state
value's or action's types (from the self String value).
Let's consider:
- unsigned integer (
0,312981,...): as state value's type - action entries (
do_it,d,...): as action kind type
Now, we can parse user input (String) to value (Integer) or
action (Action) type:
| user input | type | inner value |
|---|---|---|
String("dothis") |
Action |
do this action |
String("dothat") |
Action |
do that action |
String("123") |
Value |
123 |
... |
... |
... |
All this stuff is done by the userinput package. String input is
parsed by the UserInputStrategy object, and converted to an
AbstractUserInput child object (like an enum variant).
The undo-redo machine stores it's inner attributes (undo and redo
stacks, coloring styles, inner report). You can call any
UndoRedoMachine method as long as this doesn't change the inner
attributes, otherwise, you'll need to call methods from the
MachineController, which provides methods to handle user input
(change machine's inner state) and to update machine's report.
The machine provides four different kind of commands:
| command | alias | description |
|---|---|---|
undo |
u |
pop an element from undo stack and send it to redo stack |
redo |
r |
pop an element from redo stack and send it to undo stack |
<unsigned int> (insert) |
- | insert an element into our machine (to undo stack) |
quit |
q |
ends the machine process |
The undo command will works only if the undo stack isn't empty. The
redo command/stack follows the same rule.
Whenever a new item is pushed to our machine, the redo stack will
be clear.
This project provides four utils only:
Colors: a shortcut to use ANSI5 color escapes without code repetitionPrinter: a shortcut to avoidSytem.out.printlnin the entire codeScannerUtil: same as bullet above, but for input gettingStrategy: an interface used to return specific outputs based on a defined input
Footnotes
-
Design Patters: Elements of Reusable Object-Oriented Software is a software engineering book that describes software design patterns. You can find it at amazon website. ↩ ↩2 ↩3
-
LIFO is a principle which dictates that the most recently added element to a collection is the first one to be removed or processed. This is analogous to a stack of plates. ↩
-
Kojamp is a Java and Kotlin project manager I built. You can find more info on it's official repository ↩
-
Lexi is a hypothetical word processor that the authors use throughout the Design Patterns1 book as a running example to demonstrate different design patterns. ↩
-
ANSI escape sequences are a standard for in-band signaling to control cursor location, color, font styling, and other options on video text terminals and terminal emulators. ↩

