diff --git a/src/BankAccount.java b/src/BankAccount.java
new file mode 100644
index 0000000..e440b34
--- /dev/null
+++ b/src/BankAccount.java
@@ -0,0 +1,19 @@
+public class BankAccount {
+ private double balance;
+
+ public BankAccount(double initialBalance) {
+ this.balance = initialBalance;
+ }
+
+ public double getBalance() {
+ return balance;
+ }
+
+ public void deposit(double amount) {
+ this.balance += amount;
+ }
+
+ public void withdraw(double amount) {
+ this.balance -= amount;
+ }
+}
diff --git a/src/BaseTransaction.java b/src/BaseTransaction.java
new file mode 100644
index 0000000..21e72c0
--- /dev/null
+++ b/src/BaseTransaction.java
@@ -0,0 +1,137 @@
+import java.util.Calendar;
+import java.util.UUID;
+
+// QUESTION 1 - Extending Interface in Concrete Class (Base Class)
+
+public class BaseTransaction implements TransactionInterface {
+ protected double amount;
+ protected Calendar date;
+ protected String transactionID;
+ protected boolean isApplied = false;
+
+ public BaseTransaction(double amount) {
+ this.amount = amount;
+ this.date = Calendar.getInstance();
+ this.transactionID = UUID.randomUUID().toString().substring(0, 8); // Generates a unique short ID
+ }
+
+ @Override
+ public double getAmount() { return this.amount; } [cite: 25]
+
+ @Override
+ public Calendar getDate() { return this.date; } [cite: 26]
+
+ @Override
+ public String getTransactionID() { return this.transactionID; } [cite: 27]
+
+ @Override
+ public void printTransactionDetails() { [cite: 29]
+ System.out.println("--- Transaction Details ---");
+ System.out.println("ID: " + transactionID);
+ System.out.println("Date: " + date.getTime());
+ System.out.println("Amount: $" + amount);
+ System.out.println("Type: Generic Base Transaction");
+ }
+
+ @Override
+ public void apply(BankAccount ba) throws InsufficientFundsException { [cite: 30]
+ // This base implementation differs substantially from the subclasses as required
+ System.out.println("[BaseTransaction Log] Inspecting account. Current balance: $" + ba.getBalance()); [cite: 31]
+ this.isApplied = true;
+ }
+}
+
+// QUESTION 1 & 2 - DepositTransaction Subclass
+
+class DepositTransaction extends BaseTransaction {
+
+ public DepositTransaction(double amount) {
+ super(amount);
+ }
+
+ // Question 1: Method Overriding
+ @Override
+ public void apply(BankAccount ba) { [cite: 33]
+ ba.deposit(this.amount);
+ this.isApplied = true;
+ System.out.println("Successfully deposited $" + this.amount);
+ }
+
+ @Override
+ public void printTransactionDetails() {
+ super.printTransactionDetails();
+ System.out.println("Type: Deposit (Irreversible)"); [cite: 37]
+ System.out.println("---------------------------");
+ }
+}
+
+
+// QUESTION 1, 2, & 3 - WithdrawalTransaction Subclass
+
+class WithdrawalTransaction extends BaseTransaction {
+ private BankAccount associatedAccount; // Used for tracking the reversal
+ private double shortfallAmount = 0.0; // Track unpaid deficit if partial withdrawal happens
+
+ public WithdrawalTransaction(double amount) {
+ super(amount);
+ }
+
+ // Question 1 & Question 3 (throws keyword requirement)
+ @Override
+ public void apply(BankAccount ba) throws InsufficientFundsException { [cite: 33, 44]
+ this.associatedAccount = ba;
+ if (ba.getBalance() < this.amount) {
+ throw new InsufficientFundsException("Insufficient funds! Transaction amount: $" + this.amount + " exceeds Balance: $" + ba.getBalance()); [cite: 44]
+ }
+ ba.withdraw(this.amount);
+ this.isApplied = true;
+ System.out.println("Successfully withdrew $" + this.amount);
+ }
+
+ // Question 3: Overloaded apply() method with try...catch...finally block
+
+ public void apply(BankAccount ba, boolean partialWithdrawalAllowed) { [cite: 45, 47]
+ this.associatedAccount = ba;
+ try { [cite: 47]
+ if (ba.getBalance() <= 0) {
+ throw new InsufficientFundsException("Account balance is zero or negative. Cannot withdraw.");
+ } else if (ba.getBalance() < this.amount) {
+ // If balance is greater than 0 but less than the withdrawal amount, withdraw everything left
+ this.shortfallAmount = this.amount - ba.getBalance(); [cite: 46]
+ this.amount = ba.getBalance(); // Update transaction amount to what was actually pulled [cite: 46]
+ ba.withdraw(this.amount); [cite: 46]
+ this.isApplied = true;
+ System.out.println("Partial Withdrawal Executed! Withdrew available balance: $" + this.amount);
+ } else {
+ // Execute standard withdrawal logic
+ apply(ba);
+ }
+ } catch (InsufficientFundsException e) { [cite: 47]
+ System.out.println("[Caught Exception inside Overloaded apply]: " + e.getMessage());
+ } finally { [cite: 47]
+ System.out.println("[Finally Block Executed] Shortfall remaining to be paid: $" + shortfallAmount);
+ }
+ }
+
+ // Question 2: Reversal logic for withdrawals
+ public boolean reverse() { [cite: 38]
+ if (this.isApplied && this.associatedAccount != null) {
+ this.associatedAccount.deposit(this.amount); // Restores the balance to its original amount [cite: 39]
+ this.isApplied = false;
+ System.out.println("Withdrawal transaction " + this.transactionID + " reversed successfully.");
+ return true;
+ }
+ System.out.println("Reversal failed. Transaction was not applied.");
+ return false;
+ }
+
+ @Override
+ public void printTransactionDetails() {
+ super.printTransactionDetails();
+ System.out.println("Type: Withdrawal (Reversible)"); [cite: 37]
+ if (shortfallAmount > 0) {
+ System.out.println("Shortfall Notice: Unpaid shortage of $" + shortfallAmount); [cite: 46]
+ }
+ System.out.println("---------------------------");
+ }
+}
diff --git a/src/InsufficientFundsException.java b/src/InsufficientFundsException.java
new file mode 100644
index 0000000..c62d7aa
--- /dev/null
+++ b/src/InsufficientFundsException.java
@@ -0,0 +1,6 @@
+// QUESTION 3 - Custom Exception Class
+public class InsufficientFundsException extends Exception {
+ public InsufficientFundsException(String message) {
+ super(message);
+ }
+}
diff --git a/src/Main.java b/src/Main.java
index 584a048..c8b5e86 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -1,156 +1,74 @@
-import Lecture1_adt.*; // Import all classes from Lecture1_adt package to be used in this client code
+// Name: Fatuma Bobba
+// Registration No: SCT212-0072/2024
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.ArrayList;
-import java.util.List;
+// QUESTION 4 - Client Testing Code
-//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);
+ public static void main(String[] args) {
+ System.out.println("=== STARTING BANK TRANSACTION SYSTEM TESTS ===\n");
+
+ // Set up test account
+ BankAccount myAccount = new BankAccount(500.0);
+ System.out.println("Initial Bank Account Balance: $" + myAccount.getBalance());
+ System.out.println("------------------------------------------------");
+
+ // 1. Test Deposit Transaction
+ System.out.println("\n--- Testing Deposit Transaction ---");
+ BaseTransaction deposit = new DepositTransaction(200.0); [cite: 52]
+ try {
+ deposit.apply(myAccount); [cite: 52]
+ deposit.printTransactionDetails();
+ System.out.println("New Account Balance: $" + myAccount.getBalance());
+ } catch (InsufficientFundsException e) {
+ System.out.println(e.getMessage());
}
- 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());
- }
+ // 2. Test Successful Withdrawal Transaction
+ System.out.println("\n--- Testing Successful Withdrawal Transaction ---");
+ WithdrawalTransaction withdrawal1 = new WithdrawalTransaction(150.0); [cite: 52]
+ try {
+ withdrawal1.apply(myAccount); [cite: 52]
+ withdrawal1.printTransactionDetails();
+ System.out.println("New Account Balance: $" + myAccount.getBalance());
+ } catch (InsufficientFundsException e) {
+ System.out.println(e.getMessage());
}
- /* 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);
+ // 3. Test Question 2: Withdrawal Reversal
+ System.out.println("\n--- Testing Question 2: Reversal of Withdrawal ---");
+ withdrawal1.reverse();
+ System.out.println("Account Balance after reversal: $" + myAccount.getBalance());
+
+ // 4. Test Question 3: Exception Handling (Standard apply throwing Exception)
+ System.out.println("\n--- Testing Question 3: Exception Throwing (Insufficient Funds) ---");
+ WithdrawalTransaction expensiveWithdrawal = new WithdrawalTransaction(2000.0);
+ try {
+ expensiveWithdrawal.apply(myAccount); // This will fail and throw the exception
+ } catch (InsufficientFundsException e) {
+ System.out.println("Successfully caught expected exception: " + e.getMessage());
}
- 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());
+ // 5. Test Question 3: Overloaded apply() with Partial Withdrawal (Try/Catch/Finally)
+ System.out.println("\n--- Testing Question 3: Overloaded Partial Withdrawal Method ---");
+ // Balance is currently $700. Attempting to withdraw $1000.
+ WithdrawalTransaction partialWithdrawal = new WithdrawalTransaction(1000.0);
+ partialWithdrawal.apply(myAccount, true); // True activates the partial withdrawal catch block logic
+ partialWithdrawal.printTransactionDetails();
+ System.out.println("Final Account Balance: $" + myAccount.getBalance());
+
+ // 6. Test Hint requirement: Polymorphism & Type Casting
+ System.out.println("\n--- Testing Question 4 Hint: Type Casting to Base Object ---");
+ WithdrawalTransaction basicW = new WithdrawalTransaction(50.0); [cite: 52]
+
+ // Polymorphically mapping subtype object to base type object via type casting
+ BaseTransaction baseRef = (BaseTransaction) basicW; [cite: 53]
+
+ try {
+ // This runs the overriding apply method due to late binding polymorphism
+ baseRef.apply(myAccount); [cite: 54]
+ baseRef.printTransactionDetails();
+ } catch (InsufficientFundsException e) {
+ System.out.println(e.getMessage());
}
-
- // 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
+}
diff --git a/src/TransactionInterface.java b/src/TransactionInterface.java
new file mode 100644
index 0000000..5edfee9
--- /dev/null
+++ b/src/TransactionInterface.java
@@ -0,0 +1,9 @@
+import java.util.Calendar;
+
+public interface TransactionInterface {
+ double getAmount();
+ Calendar getDate();
+ String getTransactionID();
+ void printTransactionDetails();
+ void apply(BankAccount ba) throws InsufficientFundsException;
+}