If anyone out there is begining OOAD, like me, you might be interested in the second maintenace task proposed by Russell in his ATM simulation example. It says like that:
Many ATM's have cash dispensers that can handle two different denominations of bills - often $20 and $5 - which allows a user to request cash in any amount that is a multiple of $5. Suppose the cash dispenser in the example (which only handles $20 bills) were replaced with such a dispenser. What changes would be needed to take advantage of the enhanced capabilities of such a dispenser?
I have modified it to allow bills of $50 , $20 and $5 to be dispensed in combinations, that follow that order as long as there are bills available, to satisfy the requested amount. You can enter 0 for any amount to simulate an ATM that only holds certain types of bills. This is a description of the changes I made: You can jump to e where the question is. a) The CashDispenser class no longer holds an attribute cashonHand of type Money, but an instance of purse. b) The methods checkCashOnHand and dispenseCash in the class CashDispenser were modified to deal with purse instead of cashonHand. c) The methods that in the System Startup took a simple instance of Money, take now an array of Money to holds the amounts introduced by the operator in different types of bills. d) The class Money was added a module method. e) The class Purse holds an array of Money representing each element an amount of dollars in different types of bills. First one the dollars the cashier has in $50 bills, second one in $20 bills, and the third in $5. Thus I decided to model the types of bills as Money instances. No new classes were added here. However these instances of Money are somehow treated differently by the program. For instance at the time of creation the number of bills of type $50 is multiplied by 50, while creating the instance that holds the amount hold in $20 bills, is multiplied by 20. Also the algorithm that calculate in how many bills of a certain type will be decomposed the amount to be dispensed, has to be aware of which type is dealing with. Though the way in which the program deals with the variation of the types of bills present seems under control, would have a more object oriented solution added some value ? For instance, having modelled $50, $20 and $5 as units of Money. The way the program deals with the variation in the types of bills is just figuring out how many different bills are possible, and the programmer should create the Money array of the maximum possible length. This the new ATM2.jar ATM simulation ATM simulation 2 ATM simulation 4 [ September 01, 2002: Message edited by: Jose Botella ] [ September 03, 2002: Message edited by: Jose Botella ]
SCJP2. Please Indent your code using UBB Code
Joined: Jul 03, 2001
I think this has to do with refactoring. Current situation: warning pseudocode ahead
drawbacks: Adding more bills imply to modify both arrays. As I said above simply figure out how many different types of bills are possible, and make the array of that size beforehand. However this implies that if ATMs with several combinations of bills are likely, the method (name it A) that calculates how many bills of each type are required to dispense the requested amount, must take into acount that some of the elements of purse aren't going to be used. We can refactor to the following scenario:
This associative array makes explicit the relationship between the elements of the same level in the arrays purse and BILLVALUE. Also unlike the array implementation, using a text file to read the types of bills a given ATM will hold -data driven approach- there isn't a need for the "method A" to take into account the type of bills not supported by the ATM. drawback: Money hasn't overriden equals or hashCode. You are forced to touch Money class again. Now I will try to compare these approaches to a more proper object oriented solution: We�ve seen a relationship between the amount of dollars hold in bills of a certain type, and a money instance representing that type of bill. Just model that relationship as an attribute of the class Money.
What adds this to the HashMap solution? I cannot see anything, except that we can now use containers for the amounts and for the types of bills that aren't required to express the relationship between the instances of both. Just because the relationship has been moved into the Money class now. I used to think that modeling using data structures wasn't very object oriented (first and second approach). I used to think that the third approach could be regarded properly as object oriented. However after these examples I can see that the relationships between instances can also be set via containers. There was also a thought that it was disturbing me: A good data structure could beat an object oriented approach. Well, data structures also establish relationships.
Joined: Jul 03, 2001
There must be, however, an advantage of using the object oriented approach. Let's consider the operations of the classes now. The method decomposedAmount(Money requested) is in class Purse. It fills in an array called toDispense whose content could be like this:
Currently this method is highly dependant on the data estructure. That means that evolving from the first to the second approach would imply touching the method. Now imagine we go back to the object oriented approach and assign to Money the responsability of decomposing the amount it represents into a given type of bill ($50 , $20 or $5). The method decomposeAmount(Money requested) in class Purse calls the newly added method requested.decompose(). We can change the purse container at will without affecting the method decomposedAmout. Now it depends on the class Money, you'll say. But you are suppose to dessign classes separating what can change from what cannot. The method decomposedAmount is coupled only to the interface of Money. The implementation of Money.decompose() can vary without affecting decomposedAmount. This is the advantage the object oriented approach can yield against the data structure approach: it makes easy the maintenance.
Hmmm... Since the change involves mainly the CashDispenser, I'd start there. It seems that the setInitialCash method will either need to be 1) modified or 2) deprecated and superceded by another method, say addBills() or something like that. So, at startup, the operator would addBills(500, new Money(5)) to add 500 $5 bills and addBills(500, new Money(20)) to add 500 $20 bills. Aside from that, I can't think of any other class that would need to change. BTW, I can't seem to find the simulation.Simulation class that gets called by the CashDispenser.dispenseCash method. That method, too, seem a bit off because of the precondition of the amount requested needs to be <= cashOnHand. I would have made the method check for that condition and throw an exception if it were not met. Another thing, I'm not sure why it is necessary to pass off the responsibility of dispensing the money to the Simulation class. Smells funny to me. You'd think that a CashDispenser class would actually have the responsibility of dispensing cash rather than delegating it to another.
Junilu thanks for your ideas. The url I provided was pointing ATM.jar instead of ATM2.jar . I've corrected it now. The simulation classes are needed for the program to run. They just simulate the harware devices.