diff --git a/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java b/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java index ed81eb8..8147fc3 100644 --- a/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java +++ b/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java @@ -4,48 +4,43 @@ import java.util.Calendar; -public abstract class BaseTransaction implements TransactionInterface { - private final int amount; +public class BaseTransaction implements TransactionInterface { + private final double 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 - */ - public BaseTransaction(int amount, @NotNull Calendar date) { + public BaseTransaction(double amount, @NotNull Calendar date) { this.amount = amount; this.date = (Calendar) date.clone(); - int uniq = (int) Math.random()*10000; - transactionID = date.toString()+uniq; + int uniq = (int) (Math.random() * 10000); + transactionID = date.getTimeInMillis() + "-" + uniq; } - /** - * getAmount() - * @return integer - */ public double getAmount() { - return amount; // Because we are dealing with Value types we need not worry about what we return + return amount; } - /** - * getDate() - * @return Calendar Object - */ 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(); } - // Method to get a unique identifier for the transaction - public String getTransactionID(){ - return transactionID; + public String getTransactionID() { + return transactionID; + } + + public void printTransactionDetails() { + System.out.println("Transaction Details:"); + System.out.println(" ID: " + getTransactionID()); + System.out.println(" Date: " + getDate().getTime()); + System.out.println(" Amount: " + getAmount()); + System.out.println(" Type: " + this.getClass().getSimpleName()); + } + + public void apply(BankAccount ba) throws InsufficientFundsException { + if (ba == null) { + throw new IllegalArgumentException("BankAccount cannot be null"); + } + System.out.println("BaseTransaction.apply(): generic transaction does not change account balance."); + printTransactionDetails(); } - // 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/DepositTrasaction.java b/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java index 81afab5..6f489e5 100644 --- a/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java +++ b/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java @@ -8,23 +8,30 @@ 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; - } + + private boolean isValidDepositAmount() { + return getAmount() >= 0; } - // Method to print a transaction receipt or details - public void printTransactionDetails(){ - System.out.println("Deposit Trasaction: "+this.toString()); + @Override + public void printTransactionDetails() { + System.out.println("Deposit Transaction Details:"); + System.out.println(" ID: " + getTransactionID()); + System.out.println(" Date: " + getDate().getTime()); + System.out.println(" Amount: " + getAmount()); } - public void apply(BankAccount ba){ - double curr_balance = ba.getBalance(); - double new_balance = curr_balance + getAmount(); - ba.setBalance(new_balance); + @Override + public void apply(BankAccount ba) { + if (ba == null) { + throw new IllegalArgumentException("BankAccount cannot be null"); + } + if (!isValidDepositAmount()) { + System.out.println("Deposit failed: amount must be non-negative. Amount: " + getAmount()); + return; + } + double newBalance = ba.getBalance() + getAmount(); + ba.setBalance(newBalance); + System.out.println("DepositTransaction applied: new balance = " + newBalance); } } diff --git a/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java b/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java new file mode 100644 index 0000000..1ca37ed --- /dev/null +++ b/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java @@ -0,0 +1,19 @@ +package Lecture4_interfaces_abstract_classes; + +public class InsufficientFundsException extends Exception { + public InsufficientFundsException() { + super(); + } + + public InsufficientFundsException(String message) { + super(message); + } + + public InsufficientFundsException(String message, Throwable cause) { + super(message, cause); + } + + public InsufficientFundsException(Throwable cause) { + super(cause); + } +} diff --git a/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java b/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java index face5b6..f739ee6 100644 --- a/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java +++ b/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java @@ -5,41 +5,78 @@ import java.util.Calendar; public class WithdrawalTransaction extends BaseTransaction { + private BankAccount appliedAccount; + private double originalBalance; + private double amountNotWithdrawn; + public WithdrawalTransaction(int amount, @NotNull Calendar date) { super(amount, date); } - private boolean checkDepositAmount(int amt) { - if (amt < 0) { - return false; - } else { - return true; - } + private boolean isValidWithdrawalAmount() { + return getAmount() >= 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 + @Override public void printTransactionDetails() { - System.out.println("Deposit Trasaction: " + this.toString()); + System.out.println("Withdrawal Transaction Details:"); + System.out.println(" ID: " + getTransactionID()); + System.out.println(" Date: " + getDate().getTime()); + System.out.println(" Amount: " + getAmount()); + System.out.println(" Amount not withdrawn: " + amountNotWithdrawn); + } + + @Override + public void apply(BankAccount ba) throws InsufficientFundsException { + apply(ba, false); } - /* - Oportunity for assignment: implementing different form of withdrawal - */ - public void apply(BankAccount ba) { - double curr_balance = ba.getBalance(); - if (curr_balance > getAmount()) { - double new_balance = curr_balance - getAmount(); - ba.setBalance(new_balance); + public void apply(BankAccount ba, boolean allowPartial) throws InsufficientFundsException { + if (ba == null) { + throw new IllegalArgumentException("BankAccount cannot be null"); + } + if (!isValidWithdrawalAmount()) { + System.out.println("Withdrawal failed: amount must be non-negative. Amount: " + getAmount()); + return; + } + + amountNotWithdrawn = 0; + try { + double currBalance = ba.getBalance(); + if (currBalance <= 0) { + throw new InsufficientFundsException("No available balance for withdrawal. Current balance: " + currBalance); + } + + originalBalance = currBalance; + if (currBalance < getAmount()) { + if (!allowPartial) { + throw new InsufficientFundsException("Insufficient funds for full withdrawal. Requested: " + getAmount() + ", available: " + currBalance); + } + amountNotWithdrawn = getAmount() - currBalance; + ba.setBalance(0); + appliedAccount = ba; + System.out.println("Partial withdrawal processed. Amount withdrawn: " + currBalance + ", amount not withdrawn: " + amountNotWithdrawn); + } else { + ba.setBalance(currBalance - getAmount()); + appliedAccount = ba; + System.out.println("WithdrawalTransaction applied: new balance = " + ba.getBalance()); + } + } catch (InsufficientFundsException e) { + System.out.println("Withdrawal error: " + e.getMessage()); + throw e; + } finally { + System.out.println("Withdrawal apply() completed. Account balance after operation: " + ba.getBalance()); } } - /* - Assignment 1 Q3: Write the Reverse method - a method unique to the WithdrawalTransaction Class - */ + public boolean reverse() { + if (appliedAccount == null) { + System.out.println("No withdrawal to reverse."); + return false; + } + appliedAccount.setBalance(originalBalance); + System.out.println("Withdrawal reversed. Restored balance to " + originalBalance); + return true; + } } diff --git a/src/Main.java b/src/Main.java index 584a048..165e38b 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; @@ -143,6 +144,58 @@ public static void testTransaction4() { // Please Take a look at all the 12 transaction now and compare with the outputs of the Transaction3 class } + public static void testAdvancedTransactions() { + BankAccount account = new BankAccount(500.0); + Calendar date = new GregorianCalendar(); + + System.out.println("\n--- BaseTransaction (generic) ---"); + BaseTransaction genericTx = new BaseTransaction(100, date); + try { + genericTx.apply(account); + } catch (Exception e) { + System.out.println("Error applying generic transaction: " + e.getMessage()); + } + genericTx.printTransactionDetails(); + System.out.println("Balance after generic transaction: " + account.getBalance()); + + System.out.println("\n--- DepositTransaction ---"); + DepositTrasaction deposit = new DepositTrasaction(200, date); + deposit.apply(account); + deposit.printTransactionDetails(); + System.out.println("Balance after deposit: " + account.getBalance()); + + System.out.println("\n--- WithdrawalTransaction full withdraw ---"); + WithdrawalTransaction withdrawal = new WithdrawalTransaction(800, date); + try { + withdrawal.apply(account); + } catch (InsufficientFundsException e) { + System.out.println("Expected exception: " + e.getMessage()); + } + System.out.println("Balance after failed full withdrawal: " + account.getBalance()); + + System.out.println("\n--- WithdrawalTransaction partial withdraw ---"); + try { + withdrawal.apply(account, true); + } catch (InsufficientFundsException e) { + System.out.println("Unexpected exception: " + e.getMessage()); + } + withdrawal.printTransactionDetails(); + System.out.println("Balance after partial withdrawal: " + account.getBalance()); + + System.out.println("\n--- Reverse withdrawal ---"); + if (withdrawal.reverse()) { + System.out.println("Balance after reversal: " + account.getBalance()); + } + + System.out.println("\n--- Polymorphism check ---"); + BaseTransaction polymorphic = withdrawal; + try { + polymorphic.apply(account); + } catch (InsufficientFundsException e) { + System.out.println("Polymorphic withdrawal error: " + e.getMessage()); + } + System.out.println("Final account balance: " + account.getBalance()); + } public static void main(String[] args) { // This is the client code @@ -152,5 +205,6 @@ public static void main(String[] args) { // testTransaction2() // testTransaction3() // testTransaction4() + testAdvancedTransactions(); } } \ No newline at end of file