Overview
These instructions give further details on a set of exercises in a github repo.
That repo is to practice different kinds of code refactorings. There are several exercises, each of which starts at a git tag in the repo.
The tags for this repo are:
- 00-project-start
- 01-wrap-collection-start
- 01-wrap-collection-end
- 02-open-closed-start
- 02-open-closed-end
- 03-strategy-pattern-start
- 03-strategy-pattern-end
- 04-factory-pattern-start
- 04-factory-pattern-end
- 05-template-method-start
- 05-template-method-end
- 06-composite-object-start
- 06-composite-object-end
After cloaning, you can confirm this list by using git (not the order will be different from what is listed above):
git tag -l
Working with the repo
You will need to install a few things for this to work. Have a look here. Note, you will not need gradle installed as described there.
In addition, you probably want to install some IDE. Any of these will be fine:
Once you have a command line, git, and an IDE, you are ready to:
- the repo (do this once)
- Select an exercise and work on it
- Move to the next exercise to either review one possible solution or start another exercise
Cloning Repo
Clone this project as usual and review the tags:
git clone https://github.com/schuchert/rpn_exercises.git
cd rpn_exercises
git tag -l
Select an exercise
In the repo directory, use git branch with a tag to create a branch based on one of the exercises, i.e.,
git checkout -b <new_branch_name> <tag_name>
For example, to work on the (recommended) first exercise:
git checkout -b wrap-collection-exercise 01-wrap-collection-start
You can now make commits to this branch as you normally would use git.
Once you are done, you can compare your results to master, which has one possible solution to the problem presented in the exercise.
Before doing that, commit any changes you want to keep in the branch created for this exercise.
Currenntly Clean
Verify you are clean before comparing or switching to a different exercise.
git status
On branch wrap-collections-exercise
nothing to commit, working tree clean
Compare to one possible solution
Assuming your changes are committed and you are in the branch you created to work on
the 01-wrap-collections-start
tag, you can compare your changes to master:
git diff 01-wrap-collections-end
Switch to tag
When your repo is clean and you’ve reviewed your results against master, you can start a new exercise by following the steps in the select an exercise above above.
Wrap Collection
Get Started
git checkout -b wrap-collection-exercise 01-wrap-collection-start
Background
An actual HP Rpn Calculator never runs out of values. If your regular Java stack runs
out of values, using pop()
or peak()
throws an exception. This makes the Java Stack
abstraction different from the needs of your domain. This makes using it directly
a possible (actual in this case) voilation of the
Dependency Inversion Principle.
Goal
We want to make our stack never empty. Technically the value returned should reflect the so-called T register. We will simplify this and instead return 0 when all the user-entered values are gone. (See Rpn Description for too much detail.)
Check
When you’ve commited all your changes:
git diff 01-wrap-collection-end
Open Closed Principle
Get Started
git checkout -b open-closed-exercise 02-open-closed-start
Background
The interface to the calculator changes every time you add a new operator. This violates the Open/Closed Principle Experiment with making a change to the API and get the code to pass.
Goals
- Adding a new operator does not change the interface to the calculator
- All exisitng operators use the new approache
- The number of methods on the classs is significantly reduced
- Introduce some negative testing to make sure use of the new API produces “reasonable” errors
Check
When you’ve commited all your changes:
git diff 02-open-closed-end
Strategy Pattern
Get Started
git checkout -b strategy-pattern-exercise 03-strategy-pattern-start
Background
All of the operators look similar. Rather than writing each as its own function, we can do the same thing as a class. Note: With Java 8 we could also use Lambdas, but for now let’s take more of a traditional approach to the Stragegy Pattern.
Goals
We want to define an interface with a single method that will work all of the operators. Review each of the operators, and determine what, if anything, is common across all operators.
Once you’ve done that, create an appropraite interface, have each of the functions in its own class, which implements that interface.
Update the solution from calling a bunch of functions to instead using instances of the various subclasses of your new interface.
Check
When you’ve commited all your changes:
git diff 03-strategy-pattern-end
Factory Pattern
Get Started
git checkout -b factory-pattern-exercise 04-factory-pattern-start
Background
Goals
There’s an abundance of code in the RpnCalculator
that can be put into its own class.
Check
When you’ve commited all your changes:
git diff 04-factory-pattern-end
Template Method Pattern
Get Started
git checkout -b template-method-exercise 05-tempalte-method-start
Backgound
There’s quite a bit of duplication in all of the binary operators. Consider add versus subtract:
add | subtract |
BigDecimal rhs = values.pop(); |
BigDecimal rhs = values.pop(); |
BigDecimal lhs = values.pop(); |
BigDecimal lhs = values.pop(); |
values.push(lhs.add(rhs)); |
values.push(lhs.subtract(rhs)); |
In fact, the only difference is the calculation of the result. The “algorithm” then is:
- Acquire operands (
lhs
andrhs
) - Calculate the result (
add
orsubtract
) - Store the result (
push
)
The Template Method Pattern implements an algorithm in a (typically abstract) base class and has one or more extension points (abstarct methods) for derived classes to implement. Those derived classes fill in the details.
Goals
- Remove the dupplication between the various binary operator classes.
Check
git diff 05-template-method-end
Composit Object Pattern
Get Started
git checkout -b composite-object-exercise 06-composite-object-start
Background
We want our calculator to be “programmable.” By that, we can make our own combinariion of existing operators. For example, Pythagorean’s theorem:
\[C^2 = A^2 + B^2\] \[C = sqrt(A^2 + B^2)\]Given an a,b of (3, 4), we might do something like this with our calculator:
Entry | Values on RpnStack | Who |
3 | 3 | user |
2 | 2, 3 | user |
pow | 9 | user |
4 | 4, 9 | user |
2 | 2, 4, 9 | user |
pow | 16, 9 | user |
add | 25 | user |
sqrt | 5 | user |
Imagine if we could turn that into a program named Pythagorean:
entry | Values on RpnStack | Who |
3 | 3 | User |
4 | 4, 3 | user |
Pythagorean | 5 | user |
One way to write the program Pythagorean
might be:
entry | Values on RpnStack | Who |
Pythagorean | 4, 3 | user |
push2 | 2, 4, 3 | Pythagorean |
pow | 16, 3 | Pythagorean |
swap | 3, 16 | Pythagorean |
push2 | 2, 3, 16 | Pythagorean |
pow | 9, 16 | Pythagorean |
add | 25 | Pythagorean |
sqrt | 5 | Pythagorean |
Goals
Check
git diff 06-composite-pattern-end
Comments