Lab 12

Using Substitution for Bank Account Transactions


Introduction

We have been talking about Interfaces and Abstract Classes, let's see how they actually work.

In this lab you will be building classes of your own.  You implement several small classes to create the beginnings of a banking application. Once again, you will use the idea of substitution to create flexible, independent classes.


Tasks

Your boss has asked you to write a Banking Application.  In thinking through the process, he has decided that it would be good to use the principles of OO, substitutability, and polymorphism. 

He has decided that he wants to have the concept of a group of things, all polymorphic to each other.  For example, he wants to start with the concepts of Deposits and Withdrawals, but he wants to be able to treat them all the same without worrying about what they actually are.  He also wants to be able to easily add in additional transaction types later on (like bank fees, ATM actions, credit card payments, etc)

To get you started, he has  proposed the following interface:

  public interface Transaction
  {
     public double execute(double currentBalance);
     public void print();
  }
  

This represents the methods that must be handled by all different Transaction classes.

Notice that these two things refer to two arguments, the Date of the transaction (which we will represent as a String for now) and the double value of the transaction. It is his intention that this information would be provided to anything that is a Transaction at the time that the thing is constructed.

  1. Create the file called "Transaction.java" and set its contents to the code given above.

     

  2. Implement two kinds of Transaction: Deposit and Withdrawal. As is indicated above, both take a double and a String as a parameter.  When execute is invoked, a deposit adds its value to the current balance, while a withdrawal subtracts its value.

    If you get these built correctly, then the following tester code:

       public class TemporaryTransactionDemo
       {
          public static void main(String[] args)
          {
             Transaction[] jobs = new Transaction[4];
             jobs[0] = new Deposit(50.00,"11/06/07");
             jobs[1] = new Withdrawal(20.00,"11/07/07");
             jobs[2] = new Deposit(127.13,"11/09/07");
             jobs[3] = new Withdrawal(50.00,"11/09/07");
          
             double balance = 0.00;
          
             for (Transaction t : jobs)
             {
                t.print();
                balance = t.execute(balance);
             }
             System.out.println("Final balance is    $"+balance);
          }
       }
    Would produce something like the following result (Assuming some formatting on your part).

    DEPOSIT    04/06/07 $50.0
    WITHDRAWAL 04/07/07 $20.0
    DEPOSIT    04/09/07 $127.13
    WITHDRAWAL 04/09/07 $50.0
    Final balance is    $107.13
      
    If you have any questions concerning the status of your code at this point, ask Dr. Schafer before you move on.

     

  3. Implement a BankAccount class. BankAccounts has a SINGLE instance variable which keeps track of a collection of Transactions. A BankAccount responds to at least three messages:

    Notice that a BankAccount DOES NOT contain an instance variable concerning the balance of the Account.   Instead, it generates this value by starting with a balance of zero and executing each of the transactions in its collection.

     

  4. Implement a BankAccountDemo class to test your bank account classes. Instances of BankAccountDemo do not have any state. They respond to a demo() message by creating at least one instance of BankAccount, adding several instances of each kind of Transaction, and sending print() and balance() messages to the BankAccount.

     

  5. Implement a Lab12 class that creates an instance of BankAccountDemo and starts the demonstration.

     

  6. The solution you generated in step 2 used an interface to make Deposit and Withdrawal be substitutable for the Transaction.  We normally use interfaces when we have classes with similar method names, but no similar functionality.

    However, there is some similar functionality between Deposit and Withdrawal.  Notice there is moderate duplicate code in t the print() methods (they are NEARLY identical). 

    When you have some common code, an alternative to an interface is an abstract class.  The abstract class contains normal methods which are inherited by the subclasses, and abstract methods which the sub class much provide.

    While this is pushing the issue a little bit, convert Transaction into an abstract class that provides the common code of to its subclasses via inheritance. At first glance, it may seem like the two methods in the interface would each become an abstract method in the abstract class.  However, by refactoring print() slightly you can do most of the work through inheritance and only require a small abstract helper method (HINT HINT) to finish the method.  In other words, when you are done revising Transaction, it should contain an inherited print() method and two abstract methods (one of which is used by print() ).

    Once you are done with this conversion, refactor Deposit and Withdrawal to extend the abstract class rather than implementing the interface.  Observe that when done properly this requires NO modifications to the BankAccount or BankAccountDemo classes.

    AGAIN, if you have any questions concerning the status of your code at this point, ask Dr. Schafer before you move on.

     

     


Deliverables

Zip up the following files (and ONLY the following files) into Lab12.zip and submit via the submission system.