| id | theme | keywords | prerequisites | ||||
|---|---|---|---|---|---|---|---|
OOP-011 |
OOP |
|
Examine the code in Account.java and its three sub-classes. You will notice that where ever a money amount is required or returned -- in the methods
getAvailableBalancecreditAmountdebitAmount
the code uses float values to represent money.
This is a Very Bad Thing!
In real-world banking (or any other application involving money) we would never use a float variable to hold or calculate money values. float values are an approximate representation of a Real number (in the math sense of "Real"). They are not only inexact, but suffer from a number of mysterious failure modes where simple computations will yield the "wrong" answer. Because float values are approximations, you might do some calculation with them, and then test whether they're equal to a value, and... they're not equal.
Don't use float unless you're doing scientific programming. And then you'll want to learn much more about how float works and its limitations and gotchas.
And remember that double values are just float values with more room for precision, so even more fertile ground for numbers to not be exactly the same.
So what should we do instead?
For this assessment:
Create a class Money that stores a money quantity as two separate variables:
- a BigInteger value for the Rands, plus
- an
intfor the cents.
The class must provide the following methods on Money objects:
Money add(Money amount): Adds an arbitraryMoneyamount to the receiverMoneyobject, and returns the result as aMoneyinstance.Money subtract(Money amount): Same asadd, but subtracting.String formatAsRands(): Format theMoneyobject that receives this message as a String of the form "Rrand-value.2-digit-cents-value". (e.g. R12.03, R-99.00)
In this step, your code must pass the unit-tests provided in the MoneyTest class. You are encouraged to add more tests you may feel are necessary. Any changes to the provided tests will be overwritten.
Think about whether to make the add and subtract methods
- change the value of the receiving
Moneyobject or to - return an entirely new
Moneyobject representing the result value
Discuss with your colleagues the consequences of these choices. In the first case we'd be making Money instances mutable-- their value can change, while in the second case we'd be deciding to make Money instances immutable (value of a Money object can't be changed).
Which do you think is better? Why?
Pro Tip:
In order to make all the unit tests in MoneyTest pass, you may find it necessary to implement equals and hashCode methods in your Money implementation, overriding the methods inherited from Object.
Once you have written the Money class and your implementation passes the tests in MoneyTest, change the Account class and its sub-classes to store Money objects instead of float. i.e. Make the unit-tests for Account, SavingsAccount, CreditAccount and BusinessAccount pass.
If you have also completed the Encapsulation 1 assessment/exercise, you will notice the differences between that implementation of Money (using a long to hold the cents value) and this one.
Which implementation is better? Why?
Is either one really "better", or are they just good at different things?