diff --git a/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java b/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java
index ed81eb8..6c17d31 100644
--- a/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java
+++ b/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java
@@ -1,51 +1,78 @@
package Lecture4_interfaces_abstract_classes;
import org.jetbrains.annotations.NotNull;
-
import java.util.Calendar;
-public abstract class BaseTransaction implements TransactionInterface {
+/**
+ * Concrete class BaseTransaction representing a general financial transaction.
+ * Implements the TransactionInterface.
+ */
+public class BaseTransaction implements TransactionInterface {
private final int amount;
private final Calendar date;
private final String transactionID;
/**
- * Lecture1_adt.TransactionInterface Constructor
- * @param amount in an integer
- * @param date: Not null, and must be a Calendar object
- * @return void
- * Instialises the field, attributes of a transaction
- * Creates a object of this
+ * BaseTransaction Constructor.
+ * @param amount the transaction amount as an integer.
+ * @param date: Not null, and must be a Calendar object.
+ * Initializes the fields of a transaction and generates a unique ID.
*/
public BaseTransaction(int amount, @NotNull Calendar date) {
this.amount = amount;
this.date = (Calendar) date.clone();
- int uniq = (int) Math.random()*10000;
- transactionID = date.toString()+uniq;
+ // Correcting the precedence issue: (int) Math.random() is always 0.
+ // We cast to int after multiplying by 10000.
+ int uniq = (int) (Math.random() * 10000);
+ this.transactionID = date.toString() + uniq;
}
/**
* getAmount()
- * @return integer
+ * @return the transaction amount as a double.
*/
+ @Override
public double getAmount() {
- return amount; // Because we are dealing with Value types we need not worry about what we return
+ return amount; // Value type, safe to return directly
}
/**
* getDate()
- * @return Calendar Object
+ * @return a defensive clone of the transaction date Calendar object.
*/
+ @Override
public Calendar getDate() {
-// return date; // Because we are dealing with Reference types we need to judiciously copy what our getters return
- return (Calendar) date.clone(); // Defensive copying or Judicious Copying
+ return (Calendar) date.clone(); // Defensive copying
+ }
+
+ /**
+ * getTransactionID()
+ * @return the unique transaction identifier.
+ */
+ @Override
+ public String getTransactionID() {
+ return transactionID;
}
- // Method to get a unique identifier for the transaction
- public String getTransactionID(){
- return transactionID;
+ /**
+ * Prints the details of the transaction.
+ */
+ public void printTransactionDetails() {
+ System.out.println("--- Generic Transaction Details ---");
+ System.out.println("Transaction ID: " + getTransactionID());
+ System.out.println("Date: " + getDate().getTime());
+ System.out.println("Amount: $" + getAmount());
+ System.out.println("------------------------------------");
+ }
+
+ /**
+ * Applies the transaction on the BankAccount object.
+ * Declares that it can throw InsufficientFundsException.
+ * This generic implementation differs substantially from Deposit/Withdrawal subclasses.
+ * @param ba the BankAccount to apply the transaction to.
+ * @throws InsufficientFundsException if balance is insufficient (not thrown by this base class).
+ */
+ public void apply(BankAccount ba) throws InsufficientFundsException {
+ System.out.println("Applying BaseTransaction: Generic transaction applied. No balance changes made.");
}
- // Method to print a transaction receipt or details
- public abstract void printTransactionDetails();
- public abstract void apply(BankAccount ba);
}
diff --git a/src/Lecture4_interfaces_abstract_classes/DepositTransaction.java b/src/Lecture4_interfaces_abstract_classes/DepositTransaction.java
new file mode 100644
index 0000000..51fad0b
--- /dev/null
+++ b/src/Lecture4_interfaces_abstract_classes/DepositTransaction.java
@@ -0,0 +1,58 @@
+package Lecture4_interfaces_abstract_classes;
+
+import org.jetbrains.annotations.NotNull;
+import java.util.Calendar;
+
+/**
+ * Concrete class DepositTransaction representing a deposit transaction.
+ * Inherits from BaseTransaction.
+ */
+public class DepositTransaction extends BaseTransaction {
+
+ /**
+ * DepositTransaction Constructor.
+ * @param amount the deposit amount.
+ * @param date the transaction date.
+ */
+ public DepositTransaction(int amount, @NotNull Calendar date) {
+ super(amount, date);
+ }
+
+ /**
+ * Helper method to validate deposit amount.
+ * @param amt the amount to check.
+ * @return true if amount is positive, false otherwise.
+ */
+ private boolean checkDepositAmount(int amt) {
+ return amt >= 0;
+ }
+
+ /**
+ * Prints the details of the deposit transaction.
+ */
+ @Override
+ public void printTransactionDetails() {
+ System.out.println("--- Deposit Transaction Details ---");
+ System.out.println("Transaction ID: " + getTransactionID());
+ System.out.println("Date: " + getDate().getTime());
+ System.out.println("Amount: $" + getAmount());
+ System.out.println("------------------------------------");
+ }
+
+ /**
+ * Applies the deposit transaction by adding the amount to the bank account's balance.
+ * Overrides the apply method inherited from BaseTransaction.
+ * @param ba the BankAccount to deposit to.
+ */
+ @Override
+ public void apply(BankAccount ba) {
+ if (!checkDepositAmount((int) getAmount())) {
+ System.out.println("Deposit failed: Invalid amount.");
+ return;
+ }
+ double curr_balance = ba.getBalance();
+ double new_balance = curr_balance + getAmount();
+ ba.setBalance(new_balance);
+ System.out.println("Deposited $" + getAmount() + " successfully. New balance: $" + new_balance);
+ }
+}
diff --git a/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java b/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java
deleted file mode 100644
index 81afab5..0000000
--- a/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package Lecture4_interfaces_abstract_classes;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Calendar;
-
-public class DepositTrasaction extends BaseTransaction {
- public DepositTrasaction(int amount, @NotNull Calendar date){
- super(amount, date);
- }
- private boolean checkDepositAmount(int amt){
- if (amt < 0){
- return false;
- }
- else{
- return true;
- }
- }
-
- // Method to print a transaction receipt or details
- public void printTransactionDetails(){
- System.out.println("Deposit Trasaction: "+this.toString());
- }
-
- public void apply(BankAccount ba){
- double curr_balance = ba.getBalance();
- double new_balance = curr_balance + getAmount();
- ba.setBalance(new_balance);
- }
-}
diff --git a/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java b/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java
new file mode 100644
index 0000000..b03a135
--- /dev/null
+++ b/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java
@@ -0,0 +1,16 @@
+package Lecture4_interfaces_abstract_classes;
+
+/**
+ * Custom Exception class representing insufficient funds for withdrawal transactions.
+ * Inherits from the standard Java Exception class.
+ */
+public class InsufficientFundsException extends Exception {
+
+ /**
+ * Constructor for InsufficientFundsException.
+ * @param message The detailed error message.
+ */
+ public InsufficientFundsException(String message) {
+ super(message);
+ }
+}
diff --git a/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java b/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java
index face5b6..99fc923 100644
--- a/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java
+++ b/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java
@@ -1,45 +1,169 @@
package Lecture4_interfaces_abstract_classes;
import org.jetbrains.annotations.NotNull;
-
import java.util.Calendar;
+/**
+ * Concrete class WithdrawalTransaction representing a withdrawal transaction.
+ * Inherits from BaseTransaction.
+ */
public class WithdrawalTransaction extends BaseTransaction {
+ // State-tracking fields for reversal and partial withdrawals
+ private BankAccount appliedAccount = null;
+ private double withdrawnAmount = 0.0;
+ private boolean isApplied = false;
+ private boolean isReversed = false;
+ private double amountNotWithdrawn = 0.0;
+
+ /**
+ * WithdrawalTransaction Constructor.
+ * @param amount the withdrawal amount.
+ * @param date the transaction date.
+ */
public WithdrawalTransaction(int amount, @NotNull Calendar date) {
super(amount, date);
}
+ /**
+ * Helper method to validate deposit/withdrawal amount check.
+ * @param amt the amount to check.
+ * @return true if amount is positive, false otherwise.
+ */
private boolean checkDepositAmount(int amt) {
- if (amt < 0) {
- return false;
- } else {
- return true;
- }
+ return amt >= 0;
}
- // Method to reverse the transaction
- public boolean reverse() {
- return true;
- } // return true if reversal was successful
-
- // Method to print a transaction receipt or details
+ /**
+ * Prints the details of the withdrawal transaction.
+ */
+ @Override
public void printTransactionDetails() {
- System.out.println("Deposit Trasaction: " + this.toString());
+ System.out.println("--- Withdrawal Transaction Details ---");
+ System.out.println("Transaction ID: " + getTransactionID());
+ System.out.println("Date: " + getDate().getTime());
+ System.out.println("Amount: $" + getAmount());
+ System.out.println("Status: " + (isApplied ? (isReversed ? "Reversed" : "Applied") : "Not Applied"));
+ if (isApplied) {
+ System.out.println(" Actually Withdrawn: $" + withdrawnAmount);
+ }
+ if (amountNotWithdrawn > 0) {
+ System.out.println(" Amount Not Withdrawn (Unpaid): $" + amountNotWithdrawn);
+ }
+ System.out.println("---------------------------------------");
}
- /*
- Oportunity for assignment: implementing different form of withdrawal
+ /**
+ * Applies the withdrawal transaction on a BankAccount.
+ * Overrides the BaseTransaction apply method.
+ * @param ba the BankAccount to withdraw from.
+ * @throws InsufficientFundsException if the account balance is less than the withdrawal amount.
*/
- public void apply(BankAccount ba) {
+ @Override
+ public void apply(BankAccount ba) throws InsufficientFundsException {
double curr_balance = ba.getBalance();
- if (curr_balance > getAmount()) {
- double new_balance = curr_balance - getAmount();
- ba.setBalance(new_balance);
+ if (curr_balance < getAmount()) {
+ throw new InsufficientFundsException("Insufficient funds: Account balance is $" + curr_balance + ", but tried to withdraw $" + getAmount());
}
+ double new_balance = curr_balance - getAmount();
+ ba.setBalance(new_balance);
+
+ this.appliedAccount = ba;
+ this.withdrawnAmount = getAmount();
+ this.isApplied = true;
+ this.isReversed = false;
+ this.amountNotWithdrawn = 0.0;
+ System.out.println("Withdrew $" + getAmount() + " successfully. New balance: $" + new_balance);
}
- /*
- Assignment 1 Q3: Write the Reverse method - a method unique to the WithdrawalTransaction Class
+ /**
+ * Overloaded apply method that handles partial withdrawal.
+ * If partial is true, and the balance is insufficient but > 0, it withdraws all remaining balance.
+ * Uses try-catch-finally block to handle InsufficientFundsException.
+ * @param ba the BankAccount to withdraw from.
+ * @param partial true to allow partial withdrawal of remaining balance.
*/
-}
+ public void apply(BankAccount ba, boolean partial) {
+ if (partial) {
+ try {
+ // Attempt standard withdrawal
+ apply(ba);
+ } catch (InsufficientFundsException e) {
+ System.out.println("Standard withdrawal failed during partial attempt: " + e.getMessage());
+ double currentBalance = ba.getBalance();
+ // Check if 0 < balance < withdrawal amount
+ if (currentBalance > 0 && currentBalance < getAmount()) {
+ double originalBalance = currentBalance;
+ ba.setBalance(0.0);
+
+ this.appliedAccount = ba;
+ this.withdrawnAmount = originalBalance;
+ this.isApplied = true;
+ this.isReversed = false;
+ this.amountNotWithdrawn = getAmount() - originalBalance;
+ System.out.println("Partial withdrawal applied. Withdrew remaining balance of $" + originalBalance +
+ ". Amount not withdrawn: $" + amountNotWithdrawn);
+ } else {
+ System.out.println("Partial withdrawal failed: Account balance is $" + currentBalance +
+ ". Cannot perform withdrawal of $" + getAmount());
+ }
+ } finally {
+ System.out.println("Finished partial withdrawal execution. Current account balance: $" + ba.getBalance());
+ }
+ } else {
+ try {
+ apply(ba);
+ } catch (InsufficientFundsException e) {
+ System.out.println("Standard withdrawal failed: " + e.getMessage());
+ } finally {
+ System.out.println("Finished standard withdrawal execution. Current account balance: $" + ba.getBalance());
+ }
+ }
+ }
+
+ /**
+ * Reverses the withdrawal transaction.
+ * Restores the balance of the BankAccount it was applied to to its original amount.
+ * @return true if reversal was successful, false otherwise.
+ */
+ public boolean reverse() {
+ if (!isApplied) {
+ System.out.println("Reversal failed: Transaction was not successfully applied.");
+ return false;
+ }
+ if (isReversed) {
+ System.out.println("Reversal failed: Transaction has already been reversed.");
+ return false;
+ }
+ if (appliedAccount == null) {
+ System.out.println("Reversal failed: No associated bank account found.");
+ return false;
+ }
+ double currentBalance = appliedAccount.getBalance();
+ appliedAccount.setBalance(currentBalance + withdrawnAmount);
+ isReversed = true;
+ System.out.println("Withdrawal transaction reversed successfully. Restored $" + withdrawnAmount + " to the account.");
+ return true;
+ }
+
+ // Getters for status monitoring
+ public BankAccount getAppliedAccount() {
+ return appliedAccount;
+ }
+
+ public double getWithdrawnAmount() {
+ return withdrawnAmount;
+ }
+
+ public boolean isApplied() {
+ return isApplied;
+ }
+
+ public boolean isReversed() {
+ return isReversed;
+ }
+
+ public double getAmountNotWithdrawn() {
+ return amountNotWithdrawn;
+ }
+}
diff --git a/src/Main.java b/src/Main.java
index 584a048..7c1ef75 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -1,156 +1,250 @@
-import Lecture1_adt.*; // Import all classes from Lecture1_adt package to be used in this client code
-
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.ArrayList;
-import java.util.List;
-
-//TIP To Run code, press or
-// click the icon in the gutter.
-/*
-* Client Code for accessing the Lecture1_adt.TransactionInterface.java module
- */
-public class Main {
-
- public static void testTransaction1() {
- Calendar d1 = new GregorianCalendar(); // d1 is an Object [Objects are Reference types]
- Lecture1_adt.Transaction1 t1 = new Lecture1_adt.Transaction1(1000, d1); // amount and d1 are arguments
-
- System.out.println(t1.toString());
- System.out.println("Lecture1_adt.TransactionInterface Amount: \t " + t1.amount);
- System.out.println("Lecture1_adt.TransactionInterface Date: \t " + t1.date);
-
- // Please note that the Client Codes can access the data in the class directly through the dot operator
- // This kind of exposure is a threat to both the Representation Independence and Preservation of Invariants
- }
-
-
- /** @return a transaction of same amount as t, one month later
- * This is a PRODUCER of the class Lecture1_adt.Transaction2
- * This code will help demostrate the Design exposures still present in transaction2 class
- * */
-
- public static Transaction2 makeNextPayment(Transaction2 t) {
- Calendar d = t.getDate();
- d.add(Calendar.MONTH, 1);
- return new Transaction2(t.getAmount(), d);
- }
-
- /*
- Testing Transaction2 class
- */
- public static void testTransaction2() {
-
- Calendar d1 = new GregorianCalendar();
-
- Lecture1_adt.Transaction2 t = new Lecture1_adt.Transaction2(1000, d1);
-
- Lecture1_adt.Transaction2 modified_t = makeNextPayment(t);
-
- System.out.println("\n\nState of the Object T1 After Client Code Tried to Change the Amount");
- System.out.println("Lecture1_adt.TransactionInterface Amount: \t "+modified_t.getAmount());
- System.out.println("Lecture1_adt.TransactionInterface Date: \t "+modified_t.getDate().getTime());
-
- System.out.println("\n\nHow does T2 Look Like?????");
- System.out.println("Lecture1_adt.TransactionInterface Amount: \t "+modified_t.getAmount());
- System.out.println("Lecture1_adt.TransactionInterface Date: \t "+modified_t.getDate().getTime());
-
- /* Please note that Although we have solved the problem of Transaction1
- * And client code can no longer use the dot (.) operator to directly access the data
- * There is still some exposure especially if we pass an object of a previous Transaction2 to create a new Transaction2 object
- */
-
- }
-
-
- /** @return a list of 12 monthly payments of identical amounts
- * This code will help demostrate the Design exposures still present in transaction3 class
- * */
- public static List makeYearOfPayments (int amount) throws NullPointerException {
-
- List listOfTransaction3s = new ArrayList();
- Calendar date = new GregorianCalendar(2024, Calendar.JANUARY, 3);
-
-
- for (int i = 0; i < 12; i++) {
- listOfTransaction3s.add(new Transaction3(amount, date));
- date.add(Calendar.MONTH, 1);
- }
- return listOfTransaction3s;
- }
-
- /*
- Testing Transaction3 class
- */
- public static void testTransaction3() {
-
- List allPaymentsIn2024 = makeYearOfPayments(1000);
-
- for (Transaction3 t3 : allPaymentsIn2024) {
-
- // Display all the 12 Transactions
- for (Transaction3 transact : allPaymentsIn2024) {
- System.out.println("\n\n ::::::::::::::::::::::::::::::::::::::::::::\n");
- System.out.println("Lecture1_adt.TransactionInterface Amount: \t "+transact.getAmount());
- System.out.println("Lecture1_adt.TransactionInterface Date: \t "+transact.getDate().getTime());
- }
- }
-
- /* Please Check all the 12 transactions displayed and hwo their dates look like
- * Note that Although Transaction3 class resolves to an extent the exposure in Transaction2 class
- * There is still some exposure especially if we pass an object of a previous Transaction3 to create a
- * new Transaction3 object
- */
- }
-
-
- /** @return a list of 12 monthly payments of identical amounts
- * This code Show that by judicious copying and defensive programming we eliminate the exposure in Transaction3
- * As defined in the constructor of Transaction4 class
- * */
-
- public static List makeYearOfPaymentsFinal (int amount) throws NullPointerException {
-
- List listOfTransaction4s = new ArrayList();
- Calendar date = new GregorianCalendar(2024, Calendar.JANUARY, 3);
-
-
- for (int i = 0; i < 12; i++) {
- listOfTransaction4s.add(new Transaction4(amount, date));
- date.add(Calendar.MONTH, 1);
- }
- return listOfTransaction4s;
- }
-
- /*
- Testing Transaction3 class
- */
- public static void testTransaction4() {
-
- /*
- * Call the function to make all the Twelve transaction in a year of our business
- */
-
- List transactionsIn2024 = makeYearOfPaymentsFinal(1200);
-
- // Display all the 12 Transactions
- for (Transaction4 transact : transactionsIn2024) {
- System.out.println("\n\n ::::::::::::::::::::::::::::::::::::::::::::\n");
- System.out.println("Lecture1_adt.TransactionInterface Amount: \t "+transact.getAmount());
- System.out.println("Lecture1_adt.TransactionInterface Date: \t "+transact.getDate().getTime());
- }
-
- // Please Take a look at all the 12 transaction now and compare with the outputs of the Transaction3 class
- }
-
-
- 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
-
- // testTransaction1()
- // testTransaction2()
- // testTransaction3()
- // testTransaction4()
- }
-}
\ No newline at end of file
+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;
+import java.util.ArrayList;
+import java.util.List;
+
+//TIP To Run code, press or
+// click the icon in the gutter.
+/*
+* Client Code for accessing the Lecture1_adt.TransactionInterface.java module
+ */
+public class Main {
+
+ public static void testTransaction1() {
+ Calendar d1 = new GregorianCalendar(); // d1 is an Object [Objects are Reference types]
+ Lecture1_adt.Transaction1 t1 = new Lecture1_adt.Transaction1(1000, d1); // amount and d1 are arguments
+
+ System.out.println(t1.toString());
+ System.out.println("Lecture1_adt.TransactionInterface Amount: \t " + t1.amount);
+ System.out.println("Lecture1_adt.TransactionInterface Date: \t " + t1.date);
+
+ // Please note that the Client Codes can access the data in the class directly through the dot operator
+ // This kind of exposure is a threat to both the Representation Independence and Preservation of Invariants
+ }
+
+
+ /** @return a transaction of same amount as t, one month later
+ * This is a PRODUCER of the class Lecture1_adt.Transaction2
+ * This code will help demostrate the Design exposures still present in transaction2 class
+ * */
+
+ public static Transaction2 makeNextPayment(Transaction2 t) {
+ Calendar d = t.getDate();
+ d.add(Calendar.MONTH, 1);
+ return new Transaction2(t.getAmount(), d);
+ }
+
+ /*
+ Testing Transaction2 class
+ */
+ public static void testTransaction2() {
+
+ Calendar d1 = new GregorianCalendar();
+
+ Lecture1_adt.Transaction2 t = new Lecture1_adt.Transaction2(1000, d1);
+
+ Lecture1_adt.Transaction2 modified_t = makeNextPayment(t);
+
+ System.out.println("\n\nState of the Object T1 After Client Code Tried to Change the Amount");
+ System.out.println("Lecture1_adt.TransactionInterface Amount: \t "+modified_t.getAmount());
+ System.out.println("Lecture1_adt.TransactionInterface Date: \t "+modified_t.getDate().getTime());
+
+ System.out.println("\n\nHow does T2 Look Like?????");
+ System.out.println("Lecture1_adt.TransactionInterface Amount: \t "+modified_t.getAmount());
+ System.out.println("Lecture1_adt.TransactionInterface Date: \t "+modified_t.getDate().getTime());
+
+ /* Please note that Although we have solved the problem of Transaction1
+ * And client code can no longer use the dot (.) operator to directly access the data
+ * There is still some exposure especially if we pass an object of a previous Transaction2 to create a new Transaction2 object
+ */
+
+ }
+
+
+ /** @return a list of 12 monthly payments of identical amounts
+ * This code will help demostrate the Design exposures still present in transaction3 class
+ * */
+ public static List makeYearOfPayments (int amount) throws NullPointerException {
+
+ List listOfTransaction3s = new ArrayList();
+ Calendar date = new GregorianCalendar(2024, Calendar.JANUARY, 3);
+
+
+ for (int i = 0; i < 12; i++) {
+ listOfTransaction3s.add(new Transaction3(amount, date));
+ date.add(Calendar.MONTH, 1);
+ }
+ return listOfTransaction3s;
+ }
+
+ /*
+ Testing Transaction3 class
+ */
+ public static void testTransaction3() {
+
+ List allPaymentsIn2024 = makeYearOfPayments(1000);
+
+ for (Transaction3 t3 : allPaymentsIn2024) {
+
+ // Display all the 12 Transactions
+ for (Transaction3 transact : allPaymentsIn2024) {
+ System.out.println("\n\n ::::::::::::::::::::::::::::::::::::::::::::\n");
+ System.out.println("Lecture1_adt.TransactionInterface Amount: \t "+transact.getAmount());
+ System.out.println("Lecture1_adt.TransactionInterface Date: \t "+transact.getDate().getTime());
+ }
+ }
+
+ /* Please Check all the 12 transactions displayed and hwo their dates look like
+ * Note that Although Transaction3 class resolves to an extent the exposure in Transaction2 class
+ * There is still some exposure especially if we pass an object of a previous Transaction3 to create a
+ * new Transaction3 object
+ */
+ }
+
+
+ /** @return a list of 12 monthly payments of identical amounts
+ * This code Show that by judicious copying and defensive programming we eliminate the exposure in Transaction3
+ * As defined in the constructor of Transaction4 class
+ * */
+
+ public static List makeYearOfPaymentsFinal (int amount) throws NullPointerException {
+
+ List listOfTransaction4s = new ArrayList();
+ Calendar date = new GregorianCalendar(2024, Calendar.JANUARY, 3);
+
+
+ for (int i = 0; i < 12; i++) {
+ listOfTransaction4s.add(new Transaction4(amount, date));
+ date.add(Calendar.MONTH, 1);
+ }
+ return listOfTransaction4s;
+ }
+
+ /*
+ Testing Transaction3 class
+ */
+ public static void testTransaction4() {
+
+ /*
+ * Call the function to make all the Twelve transaction in a year of our business
+ */
+
+ List transactionsIn2024 = makeYearOfPaymentsFinal(1200);
+
+ // Display all the 12 Transactions
+ for (Transaction4 transact : transactionsIn2024) {
+ System.out.println("\n\n ::::::::::::::::::::::::::::::::::::::::::::\n");
+ System.out.println("Lecture1_adt.TransactionInterface Amount: \t "+transact.getAmount());
+ System.out.println("Lecture1_adt.TransactionInterface Date: \t "+transact.getDate().getTime());
+ }
+
+ // Please Take a look at all the 12 transaction now and compare with the outputs of the Transaction3 class
+ }
+
+
+ public static void testLecture4Transactions() {
+ System.out.println("\n==================================================");
+ System.out.println(" TESTING LECTURE 4 TRANSACTIONS ");
+ System.out.println("==================================================");
+
+ // 1. Create a BankAccount with a starting balance
+ BankAccount account = new BankAccount(500.0);
+ System.out.println("Created BankAccount with initial balance: $" + account.getBalance());
+
+ // 2. Test DepositTransaction
+ Calendar d1 = new GregorianCalendar(2026, Calendar.JUNE, 9);
+ DepositTransaction deposit = new DepositTransaction(200, d1);
+ System.out.println("\nApplying Deposit of $200...");
+ deposit.apply(account);
+ deposit.printTransactionDetails();
+
+ // 3. Test WithdrawalTransaction (Successful Standard Withdrawal)
+ Calendar d2 = new GregorianCalendar(2026, Calendar.JUNE, 9);
+ WithdrawalTransaction withdrawal1 = new WithdrawalTransaction(150, d2);
+ System.out.println("\nApplying Withdrawal of $150 (standard)...");
+ try {
+ withdrawal1.apply(account);
+ } catch (InsufficientFundsException e) {
+ System.out.println("Caught Expected Exception: " + e.getMessage());
+ }
+ withdrawal1.printTransactionDetails();
+
+ // 4. Test Reversal of WithdrawalTransaction
+ System.out.println("\nReversing the $150 Withdrawal...");
+ withdrawal1.reverse();
+ System.out.println("Balance after reversal: $" + account.getBalance());
+
+ // Try to reverse again to check idempotency/prevention of double reversal
+ System.out.println("Attempting to reverse the withdrawal again...");
+ withdrawal1.reverse();
+
+ // 5. Test WithdrawalTransaction (Insufficient Funds - Exception Thrown)
+ WithdrawalTransaction withdrawalTooBig = new WithdrawalTransaction(1000, d2);
+ System.out.println("\nApplying Withdrawal of $1000 (exceeds balance)...");
+ try {
+ withdrawalTooBig.apply(account);
+ } catch (InsufficientFundsException e) {
+ System.out.println("Caught Expected Exception for insufficient funds: " + e.getMessage());
+ }
+ withdrawalTooBig.printTransactionDetails();
+
+ // 6. Test Overloaded apply() for partial withdrawal (when 0 < balance < withdrawal)
+ // Set balance to a value less than withdrawal amount but greater than 0
+ account.setBalance(300.0);
+ System.out.println("\nSet account balance to: $" + account.getBalance());
+ WithdrawalTransaction withdrawalPartial = new WithdrawalTransaction(500, d2);
+ System.out.println("Applying Withdrawal of $500 with partial option allowed...");
+ withdrawalPartial.apply(account, true);
+ withdrawalPartial.printTransactionDetails();
+
+ // Reverse the partial withdrawal to verify restoring exact withdrawn amount
+ System.out.println("\nReversing the partial withdrawal...");
+ withdrawalPartial.reverse();
+ System.out.println("Balance after partial reversal: $" + account.getBalance());
+
+ // 7. Test polymorphism and early/late binding
+ System.out.println("\n--- Testing Polymorphism and Dynamic Binding ---");
+
+ // Map subclass objects to the BaseTransaction reference
+ BaseTransaction baseRef1 = deposit;
+ BaseTransaction baseRef2 = withdrawalTooBig;
+
+ System.out.println("1) Casting DepositTransaction to BaseTransaction reference:");
+ try {
+ baseRef1.apply(account); // Late binding calls DepositTransaction.apply()
+ } catch (InsufficientFundsException e) {
+ System.out.println("Error: " + e.getMessage());
+ }
+
+ System.out.println("\n2) Casting WithdrawalTransaction to BaseTransaction reference (throws exception):");
+ try {
+ baseRef2.apply(account); // Late binding calls WithdrawalTransaction.apply()
+ } catch (InsufficientFundsException e) {
+ System.out.println("Caught exception via polymorphic BaseTransaction reference call: " + e.getMessage());
+ }
+
+ // Test calling BaseTransaction's own apply()
+ BaseTransaction baseTx = new BaseTransaction(100, d2);
+ System.out.println("\n3) Direct execution of BaseTransaction.apply():");
+ try {
+ baseTx.apply(account); // Early binding calls BaseTransaction.apply()
+ } catch (InsufficientFundsException e) {
+ System.out.println("Error: " + e.getMessage());
+ }
+ baseTx.printTransactionDetails();
+ }
+
+ 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
+
+ // testTransaction1()
+ // testTransaction2()
+ // testTransaction3()
+ // testTransaction4()
+ testLecture4Transactions();
+ }
+}
\ No newline at end of file