diff --git a/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java b/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java
index ed81eb8..23e4afe 100644
--- a/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java
+++ b/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java
@@ -4,7 +4,13 @@
import java.util.Calendar;
-public abstract class BaseTransaction implements TransactionInterface {
+/**
+ * Concrete class that implements the TransactionInterface.
+ * This class provides a base implementation for all transaction types.
+ * Subclasses (DepositTransaction, WithdrawalTransaction) override the apply() method
+ * to provide specific transaction behavior (polymorphism via late binding).
+ */
+public class BaseTransaction implements TransactionInterface {
private final int amount;
private final Calendar date;
private final String transactionID;
@@ -26,7 +32,7 @@ public BaseTransaction(int amount, @NotNull Calendar date) {
/**
* getAmount()
- * @return integer
+ * @return double - the transaction amount
*/
public double getAmount() {
return amount; // Because we are dealing with Value types we need not worry about what we return
@@ -45,7 +51,29 @@ public Calendar getDate() {
public String getTransactionID(){
return transactionID;
}
- // Method to print a transaction receipt or details
- public abstract void printTransactionDetails();
- public abstract void apply(BankAccount ba);
+
+ /**
+ * printTransactionDetails()
+ * Prints out the details of this transaction including the amount, date, and transaction ID.
+ */
+ public void printTransactionDetails(){
+ System.out.println("Transaction Details:");
+ System.out.println("Transaction ID: \t" + transactionID);
+ System.out.println("Transaction Amount: \t" + amount);
+ System.out.println("Transaction Date: \t" + date.getTime());
+ }
+
+ /**
+ * apply(BankAccount ba)
+ * Base implementation of apply - simply prints the transaction details.
+ * This differs from DepositTransaction (which adds to balance) and
+ * WithdrawalTransaction (which subtracts from balance).
+ * Subclasses override this method to provide specific behavior (late binding).
+ * @param ba the BankAccount object to apply the transaction on
+ */
+ public void apply(BankAccount ba) throws InsufficientFundsException {
+ System.out.println("Base Transaction Applied:");
+ printTransactionDetails();
+ System.out.println("Current Balance After Base Apply: \t" + ba.getBalance());
+ }
}
diff --git a/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java b/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java
index 81afab5..25a2708 100644
--- a/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java
+++ b/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java
@@ -4,6 +4,11 @@
import java.util.Calendar;
+/**
+ * DepositTransaction extends BaseTransaction.
+ * Deposits are irreversible - once applied, they cannot be undone.
+ * Overrides the apply() method to add the deposit amount to the bank account balance.
+ */
public class DepositTrasaction extends BaseTransaction {
public DepositTrasaction(int amount, @NotNull Calendar date){
super(amount, date);
@@ -19,12 +24,24 @@ private boolean checkDepositAmount(int amt){
// Method to print a transaction receipt or details
public void printTransactionDetails(){
- System.out.println("Deposit Trasaction: "+this.toString());
+ System.out.println("Deposit Transaction: " + this.toString());
+ System.out.println("Amount Deposited: \t" + getAmount());
+ System.out.println("Transaction Date: \t" + getDate().getTime());
+ System.out.println("Transaction ID: \t" + getTransactionID());
}
- public void apply(BankAccount ba){
+ /**
+ * apply(BankAccount ba)
+ * Overrides BaseTransaction.apply() to add the deposit amount to the account balance.
+ * This implementation differs from BaseTransaction (which only prints details) and
+ * WithdrawalTransaction (which subtracts from balance).
+ * @param ba the BankAccount object to apply the deposit on
+ */
+ @Override
+ public void apply(BankAccount ba) throws InsufficientFundsException {
double curr_balance = ba.getBalance();
double new_balance = curr_balance + getAmount();
ba.setBalance(new_balance);
+ System.out.println("Deposit Applied Successfully. New Balance: " + ba.getBalance());
}
}
diff --git a/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java b/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java
new file mode 100644
index 0000000..137e6a9
--- /dev/null
+++ b/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java
@@ -0,0 +1,38 @@
+package Lecture4_interfaces_abstract_classes;
+
+/**
+ * Custom Exception class to handle insufficient funds during withdrawal transactions.
+ * Extends Exception to make it a checked exception, enforcing proper error handling.
+ */
+public class InsufficientFundsException extends Exception {
+
+ private final double amount;
+ private final double balance;
+
+ /**
+ * Constructor for InsufficientFundsException
+ * @param amount the withdrawal amount that was attempted
+ * @param balance the current balance in the account
+ */
+ public InsufficientFundsException(double amount, double balance) {
+ super("Insufficient Funds: Attempted to withdraw " + amount + " but only " + balance + " available.");
+ this.amount = amount;
+ this.balance = balance;
+ }
+
+ /**
+ * getAmount()
+ * @return the amount that was attempted to be withdrawn
+ */
+ public double getAmount() {
+ return amount;
+ }
+
+ /**
+ * getBalance()
+ * @return the balance at the time of the failed transaction
+ */
+ public double getBalance() {
+ return balance;
+ }
+}
diff --git a/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java b/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java
index face5b6..0f88b0c 100644
--- a/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java
+++ b/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java
@@ -4,12 +4,26 @@
import java.util.Calendar;
+/**
+ * WithdrawalTransaction extends BaseTransaction.
+ * Withdrawals can be reversed - the reverse() method restores the bank account balance.
+ * Overrides the apply() method to subtract the withdrawal amount from the bank account balance.
+ * Implements exception handling for insufficient funds.
+ */
public class WithdrawalTransaction extends BaseTransaction {
+
+ private double amountNotWithdrawn; // Keeps a record of the amount not withdrawn
+ private boolean applied; // Tracks whether this transaction has been applied
+ private BankAccount targetAccount; // Reference to the account the transaction was applied on
+
public WithdrawalTransaction(int amount, @NotNull Calendar date) {
super(amount, date);
+ this.amountNotWithdrawn = 0;
+ this.applied = false;
+ this.targetAccount = null;
}
- private boolean checkDepositAmount(int amt) {
+ private boolean checkWithdrawalAmount(int amt) {
if (amt < 0) {
return false;
} else {
@@ -17,29 +31,107 @@ private boolean checkDepositAmount(int amt) {
}
}
- // Method to reverse the transaction
+ /**
+ * reverse()
+ * Reverses the withdrawal transaction by restoring the balance to the bank account.
+ * Only succeeds if the transaction was previously applied.
+ * @return true if reversal was successful, false otherwise
+ */
public boolean reverse() {
+ if (!applied || targetAccount == null) {
+ System.out.println("Withdrawal Transaction has not been applied yet. Cannot reverse.");
+ return false;
+ }
+
+ // Restore the withdrawn amount (which is getAmount() - amountNotWithdrawn)
+ double withdrawnAmount = getAmount() - amountNotWithdrawn;
+ double currentBalance = targetAccount.getBalance();
+ targetAccount.setBalance(currentBalance + withdrawnAmount);
+ System.out.println("Withdrawal Reversed Successfully. New Balance: " + targetAccount.getBalance());
+ applied = false;
return true;
- } // return true if reversal was successful
+ }
// Method to print a transaction receipt or details
public void printTransactionDetails() {
- System.out.println("Deposit Trasaction: " + this.toString());
+ System.out.println("Withdrawal Transaction: " + this.toString());
+ System.out.println("Amount Withdrawn: \t" + getAmount());
+ System.out.println("Transaction Date: \t" + getDate().getTime());
+ System.out.println("Transaction ID: \t" + getTransactionID());
+ if (amountNotWithdrawn > 0) {
+ System.out.println("Amount Not Withdrawn: \t" + amountNotWithdrawn);
+ }
+ }
+
+ /**
+ * apply(BankAccount ba)
+ * Overrides BaseTransaction.apply() to subtract the withdrawal amount from the account balance.
+ * Uses the throws keyword to handle InsufficientFundsException when the balance
+ * is less than the withdrawal amount.
+ * @param ba the BankAccount object to apply the withdrawal on
+ * @throws InsufficientFundsException if the balance is less than the withdrawal amount
+ */
+ @Override
+ public void apply(BankAccount ba) throws InsufficientFundsException {
+ double curr_balance = ba.getBalance();
+ if (curr_balance < getAmount()) {
+ throw new InsufficientFundsException(getAmount(), curr_balance);
+ }
+ double new_balance = curr_balance - getAmount();
+ ba.setBalance(new_balance);
+ this.applied = true;
+ this.targetAccount = ba;
+ System.out.println("Withdrawal Applied Successfully. New Balance: " + ba.getBalance());
}
- /*
- Oportunity for assignment: implementing different form of withdrawal
+ /**
+ * Overloaded apply() method (Q3)
+ * Not only checks if the balance covers the withdrawal amount but also checks
+ * if the balance is greater than 0. In the case when 0 < balance < withdrawal amount,
+ * it withdraws all the balance and keeps a record of the amount not withdrawn.
+ * Implements exception handling using try{...} catch{...} finally{...} block.
+ * @param ba the BankAccount object to apply the withdrawal on
+ * @param checkAvailableBalance flag to indicate that this overloaded version should be used
*/
- public void apply(BankAccount ba) {
+ public void apply(BankAccount ba, boolean checkAvailableBalance) {
double curr_balance = ba.getBalance();
- if (curr_balance > getAmount()) {
+
+ try {
+ // Check if the balance covers the withdrawal amount
+ if (curr_balance < getAmount()) {
+ throw new InsufficientFundsException(getAmount(), curr_balance);
+ }
+
+ // Sufficient funds - withdraw the full amount
double new_balance = curr_balance - getAmount();
ba.setBalance(new_balance);
+ this.amountNotWithdrawn = 0;
+ System.out.println("Withdrawal Applied Successfully. New Balance: " + ba.getBalance());
+
+ } catch (InsufficientFundsException e) {
+ // If the balance is greater than 0 but less than the withdrawal amount
+ // Withdraw all the available balance and keep a record of the amount not withdrawn
+ if (curr_balance > 0) {
+ this.amountNotWithdrawn = getAmount() - curr_balance;
+ ba.setBalance(0);
+ System.out.println("Partial Withdrawal: Only " + curr_balance + " was available.");
+ System.out.println("Amount Not Withdrawn: " + amountNotWithdrawn);
+ } else {
+ this.amountNotWithdrawn = getAmount();
+ System.out.println("Error: " + e.getMessage());
+ }
+ } finally {
+ this.applied = true;
+ this.targetAccount = ba;
+ System.out.println("Transaction Complete. Final Balance: " + ba.getBalance());
}
}
- /*
- Assignment 1 Q3: Write the Reverse method - a method unique to the WithdrawalTransaction Class
+ /**
+ * getAmountNotWithdrawn()
+ * @return the amount that could not be withdrawn due to insufficient funds
*/
+ public double getAmountNotWithdrawn() {
+ return amountNotWithdrawn;
+ }
}
-
diff --git a/src/Main.java b/src/Main.java
index 584a048..de006de 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -1,4 +1,5 @@
import Lecture1_adt.*; // Import all classes from Lecture1_adt package to be used in this client code
+import Lecture4_interfaces_abstract_classes.*;
import java.util.Calendar;
import java.util.GregorianCalendar;
@@ -8,7 +9,7 @@
//TIP To Run code, press or
// click the icon in the gutter.
/*
-* Client Code for accessing the Lecture1_adt.TransactionInterface.java module
+ * Client Code for accessing the Lecture1_adt.TransactionInterface.java module
*/
public class Main {
@@ -144,6 +145,144 @@ public static void testTransaction4() {
}
+ /*
+ * ====================================================================
+ * Assignment 1 - Question 4: Client Code to test Assignment classes
+ * ====================================================================
+ */
+
+ /**
+ * Test the DepositTransaction class
+ * Creates a DepositTransaction, applies it to a BankAccount, and prints details.
+ */
+ public static void testDepositTransaction() {
+ System.out.println("=============================================");
+ System.out.println(" Testing DepositTransaction");
+ System.out.println("=============================================");
+
+ // Create a BankAccount with initial balance of 1000
+ BankAccount account = new BankAccount(1000);
+ System.out.println("Initial Balance: \t" + account.getBalance());
+
+ // Create a DepositTransaction of 500
+ Calendar date = new GregorianCalendar();
+ DepositTrasaction deposit = new DepositTrasaction(500, date);
+
+ // Print the transaction details
+ deposit.printTransactionDetails();
+
+ // Apply the deposit to the bank account
+ try {
+ deposit.apply(account);
+ } catch (InsufficientFundsException e) {
+ System.out.println("Error: " + e.getMessage());
+ }
+ System.out.println("Balance After Deposit: \t" + account.getBalance());
+
+ System.out.println("\n--- Testing Polymorphism: Type casting DepositTransaction to BaseTransaction ---");
+
+ // Type casting: Assign the subtype object to a base type reference (early vs late binding)
+ BaseTransaction baseRef = deposit; // Upcasting - subtype to base type
+ System.out.println("\nCalling apply() through BaseTransaction reference (late binding):");
+ try {
+ baseRef.apply(new BankAccount(2000)); // Late binding: calls DepositTrasaction.apply()
+ } catch (InsufficientFundsException e) {
+ System.out.println("Error: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Test the WithdrawalTransaction class
+ * Tests normal withdrawal, insufficient funds exception, partial withdrawal, and reversal.
+ */
+ public static void testWithdrawalTransaction() {
+ System.out.println("\n\n=============================================");
+ System.out.println(" Testing WithdrawalTransaction");
+ System.out.println("=============================================");
+
+ // Create a BankAccount with initial balance of 1000
+ BankAccount account = new BankAccount(1000);
+ System.out.println("Initial Balance: \t" + account.getBalance());
+
+ // --- Test 1: Normal Withdrawal ---
+ System.out.println("\n--- Test 1: Normal Withdrawal of 300 ---");
+ Calendar date1 = new GregorianCalendar();
+ WithdrawalTransaction withdrawal1 = new WithdrawalTransaction(300, date1);
+ withdrawal1.printTransactionDetails();
+ try {
+ withdrawal1.apply(account);
+ } catch (InsufficientFundsException e) {
+ System.out.println("Error: " + e.getMessage());
+ }
+ System.out.println("Balance After Withdrawal: \t" + account.getBalance());
+
+ // --- Test 2: Reversal of the Withdrawal ---
+ System.out.println("\n--- Test 2: Reversing the Withdrawal of 300 ---");
+ boolean reversed = withdrawal1.reverse();
+ System.out.println("Reversal Successful: \t" + reversed);
+ System.out.println("Balance After Reversal: \t" + account.getBalance());
+
+ // --- Test 3: Withdrawal with Insufficient Funds (throws exception) ---
+ System.out.println("\n--- Test 3: Withdrawal of 5000 with Insufficient Funds (throws) ---");
+ Calendar date2 = new GregorianCalendar();
+ WithdrawalTransaction withdrawal2 = new WithdrawalTransaction(5000, date2);
+ try {
+ withdrawal2.apply(account);
+ } catch (InsufficientFundsException e) {
+ System.out.println("Exception Caught: " + e.getMessage());
+ }
+ System.out.println("Balance After Failed Withdrawal: \t" + account.getBalance());
+
+ // --- Test 4: Partial Withdrawal using overloaded apply() with try-catch-finally ---
+ System.out.println("\n--- Test 4: Partial Withdrawal of 5000 using overloaded apply() ---");
+ Calendar date3 = new GregorianCalendar();
+ WithdrawalTransaction withdrawal3 = new WithdrawalTransaction(5000, date3);
+ withdrawal3.apply(account, true);
+ System.out.println("Amount Not Withdrawn: \t" + withdrawal3.getAmountNotWithdrawn());
+
+ // --- Test 5: Polymorphism - Type casting to BaseTransaction ---
+ System.out.println("\n--- Test 5: Polymorphism - Type Casting WithdrawalTransaction to BaseTransaction ---");
+ BankAccount account2 = new BankAccount(2000);
+ Calendar date4 = new GregorianCalendar();
+ WithdrawalTransaction withdrawal4 = new WithdrawalTransaction(500, date4);
+
+ // Upcasting: subtype object to base type reference
+ BaseTransaction baseRef = withdrawal4;
+ System.out.println("Calling apply() through BaseTransaction reference (late binding):");
+ try {
+ baseRef.apply(account2); // Late binding: calls WithdrawalTransaction.apply()
+ } catch (InsufficientFundsException e) {
+ System.out.println("Exception Caught: " + e.getMessage());
+ }
+ System.out.println("Balance After Polymorphic Withdrawal: \t" + account2.getBalance());
+ }
+
+ /**
+ * Test the BaseTransaction class directly
+ * Shows how the BaseTransaction.apply() differs from subclass implementations.
+ */
+ public static void testBaseTransaction() {
+ System.out.println("\n\n=============================================");
+ System.out.println(" Testing BaseTransaction (directly)");
+ System.out.println("=============================================");
+
+ BankAccount account = new BankAccount(1000);
+ Calendar date = new GregorianCalendar();
+ BaseTransaction baseTransaction = new BaseTransaction(100, date);
+
+ System.out.println("Initial Balance: \t" + account.getBalance());
+ baseTransaction.printTransactionDetails();
+
+ try {
+ baseTransaction.apply(account);
+ } catch (InsufficientFundsException e) {
+ System.out.println("Error: " + e.getMessage());
+ }
+ System.out.println("Balance After Base Apply: \t" + account.getBalance());
+ // Note: BaseTransaction.apply() does NOT change the balance - it only prints details
+ }
+
+
public static void main(String[] args) {
// This is the client code
// Uncomment the following lines to test the class which you would like to test
@@ -152,5 +291,12 @@ public static void main(String[] args) {
// testTransaction2()
// testTransaction3()
// testTransaction4()
+
+ /*
+ * Assignment 1 - Question 4: Test the Assignment classes
+ */
+ testBaseTransaction();
+ testDepositTransaction();
+ testWithdrawalTransaction();
}
}
\ No newline at end of file