Lab #2: Object-based programming essentials Get this lab checked off by a TA by the last lab on Friday 17 September. In lecture, we saw a simple Account class, representing a bank account. In this lab, we will elaborate on it a bit in order to exercise the basic mechanisms of object-based programming in Java. 1. Be sure you have all the files associated with this lab, which are DIRECTIONS This file Makefile The makefile controlling compilation and testing. Banking.java The main program for the application we are developing. test1.in, test1.out An input script and expected output for testing the application. bank A directory containing the bank PACKAGE, a collection of Java classes. Initially, the only file here is: bank/Account.java Containing the class bank.Account, adapted from lecture. bank/Bank.java Currently unused. You will augment this. Tests.commands A simple testing script that runs the banking program with test1.in as input, and compares the output against test1.out Tests.java.template Tests.test.template Templates that are used with Tests.commands to create a testing file called Tests.java 2. First, compile everything using gmake and run it to see what it does. 3. Currently, the Account.deposit method allows negative deposits, and Account.withdraw allows negative withdrawals. Also, it is possible to withdraw more funds than there are in the bank. Modify bank/Account.java to signal these errors (see how it currently handles an attempt to withdraw too much). 4. Type 'gmake check' and see what happens. The tests given are quite minimal. Add additional test files (DON'T modify test1.in and test1.out) that test more of the application, including situations that cause errors. Figure out the appropriate modifications to Tests.java. Also, when you do later parts of this lab, each time some bug in your program causes an error, ADD A NEW TEST that tries to tickle that bug (this is known as "regression testing"). 5. Adding tests analogous to test1.in and test1.out to Tests.commands is rather tedious. The only thing that changes from one test to the next are the names of the test input and output files. How would you change Tests.java.template and Tests.commands to make it easier to add more such tests to Tests.commands? 6. Currently, the total funds in the bank are represented as a static (class) variable. That effectively means that there is only one bank in the universe for Accounts to draw on---not very realistic. In the following steps, we're going to enhance the package to introduce a new class: bank.Bank, and connect each new account to a Bank. 7. As a first step, let's change the way that Accounts are created. In real life, one doesn't create an account out of thin air; instead, you ask a bank for an account (well, the usual terminology is "open an account at a bank"). As a first step, add a new instance method to Bank (in file bank/Bank.java) called openAccount, which takes an initial amount of money and creates a new Account with that initial balance. Change Banking.java to create a Bank at the beginning and to use openAccount on that bank rather than executing 'new Account(0)' directly. Finally, change Makefile to reflect this new source file. Don't change anything else at this point. The Bank at this point won't be terribly useful, since all it will do is create accounts. Compile and test to make sure you haven't broken anything. 8. To make sure you're doing this right, remove the keyword 'public' from the Account constructor in bank/Account.java (so that you can't perform 'new Account(...)' from within the file Banking.java) and make sure everything still compiles. We haven't talked about public, private, and default access yet In a nutshell: a. A 'public' method or field is available from any other class. b. A 'private' method or field is available only inside the class that defines it. c. An unmarked method or field is available only inside the PACKAGE that contains the class that declares it. Thus, the public method Account.withdraw (in package bank) can be called from inside Banking (in the "anonymous" package), but the default-access constructor Account (i.e., the Account constructor once you remove the 'public' modifier) cannot. The constructor CAN, however, be called from within Bank, because Bank is also defined in package 'bank'. 9. Add a new private instance variable called 'bank' to Account that keeps track of what Bank it belongs to (we won't do anything with it just now, but we're going to need it later). Somehow you have to arrange that when Bank.openAccount creates a new Account, the new Account's bank field gets set. openAccount can't assign to it directly, because I said to make the field private to Account. Assume that Accounts never move from Bank to Bank, but are permanently attached to the Bank that created them. What do you think is a sensible way to arrange that the 'bank' field of each new Account points to the Bank that creates the account? Make any changes you need to constructors, methods, etc., in Bank.java and in Account.java. As usual, make sure your program still compiles and runs. 10. Now remove the static variable 'funds' and the static method 'funds()' from Account. In their place, a. Put a private 'funds' instance variable (NOT static) in Bank. b. Add two instance methods to Bank with default access (no keyword 'public' or 'private'): one to add funds to the bank, and one to withdraw them. c. Add a public method to Bank to query the current total funds in the bank. d. Make any necessary changes to Account.java and Banking.java to use this new representation. e. As usual, compile and test your program. SANITY CHECK: There should be no static variables in your files. CHECK OFFS: Show the results of your labors to your TA. As well as explaining what you've done, be prepared to explain the rest of the code in Banking.java (i.e., the stuff WE wrote), and the contents of Makefile. That means that you should read it and ask or read about parts you don't understand (for that matter, do this with ALL program text we give you!) We have NOT talked about all of it in lecture!