Port of schuchert.wikispaces.com


Rpn Calculator Exercises

Rpn Calculator Exercises

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:

  1. 00-project-start
  2. 01-wrap-collection-start
  3. 01-wrap-collection-end
  4. 02-open-closed-start
  5. 02-open-closed-end
  6. 03-strategy-pattern-start
  7. 03-strategy-pattern-end
  8. 04-factory-pattern-start
  9. 04-factory-pattern-end
  10. 05-template-method-start
  11. 05-template-method-end
  12. 06-composite-object-start
  13. 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. Image of 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

Image of Abstract Factory

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:

  1. Acquire operands (lhs and rhs)
  2. Calculate the result (add or subtract)
  3. 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.

Image of Template Method Pattern

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

Image of Composite Pattern

Goals

Check

git diff 06-composite-pattern-end

Comments

" Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.