diff --git a/.gitignore b/.gitignore index f68d109..ec1bc63 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,29 @@ -### IntelliJ IDEA ### -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -### Mac OS ### +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### .DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore index 13566b8..1c2fda5 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -1,8 +1,8 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/misc.xml b/.idea/misc.xml index 1b2d693..7de4ee7 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 4030c30..e8bee7e 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -1,8 +1,8 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml index 2b63946..6d50cd4 100644 --- a/.idea/uiDesigner.xml +++ b/.idea/uiDesigner.xml @@ -1,124 +1,124 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..9661ac7 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/AdvancedProgramming.iml b/AdvancedProgramming.iml index c29f477..565627f 100644 --- a/AdvancedProgramming.iml +++ b/AdvancedProgramming.iml @@ -1,20 +1,20 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 99b7168..4b25ab2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# Advanced-Programming -A Repository for Programming Exercises and Assignments in Advanced Programming +# Advanced-Programming +A Repository for Programming Exercises and Assignments in Advanced Programming diff --git a/src/Lecture1_adt/Transaction1.java b/src/Lecture1_adt/Transaction1.java index 8a46bd5..1c4bf95 100644 --- a/src/Lecture1_adt/Transaction1.java +++ b/src/Lecture1_adt/Transaction1.java @@ -1,18 +1,18 @@ -package Lecture1_adt; - -import java.util.Calendar; - -/** - * This Lecture1_adt.TransactionInterface Class violates several ADT design principles: - * 1. Representation Independence: --- Changes in representation of the data may require external code to alter access - * 2. Preservation of Invariants: --- Any external client code can alter the internal values - */ -public class Transaction1 { - public int amount; - public Calendar date; - - public Transaction1(int amount, Calendar date) { - this.amount = amount; - this.date = (Calendar) date.clone(); - } -} +package Lecture1_adt; + +import java.util.Calendar; + +/** + * This Lecture1_adt.TransactionInterface Class violates several ADT design principles: + * 1. Representation Independence: --- Changes in representation of the data may require external code to alter access + * 2. Preservation of Invariants: --- Any external client code can alter the internal values + */ +public class Transaction1 { + public int amount; + public Calendar date; + + public Transaction1(int amount, Calendar date) { + this.amount = amount; + this.date = (Calendar) date.clone(); + } +} diff --git a/src/Lecture1_adt/Transaction2.java b/src/Lecture1_adt/Transaction2.java index 6c7a010..3f90c1c 100644 --- a/src/Lecture1_adt/Transaction2.java +++ b/src/Lecture1_adt/Transaction2.java @@ -1,36 +1,36 @@ -package Lecture1_adt; - -import org.jetbrains.annotations.NotNull; - -import java.util.Calendar; -//import java.util.Date; - -/** - * This Lecture1_adt.Transaction2 Class Takes the first step to resolves the ADT design issues of Transaction1: - * 1. Representation Independence: --- Encapsulation - Providing access methods to the internal data. - * External client code only access via allowable operations - * --- Changes to internal representation can still be accessed via same methods defined - * - * 2. Preservation of Invariants: --- Access Modifies private final makes the data Unchangeable - * - * Lecture1_adt - */ - -public class Transaction2 { - private final int amount; - private final Calendar date; - - public Transaction2(int amount, @NotNull Calendar date) { - this.amount = amount; - this.date = date; - } - - public int getAmount() { - return amount; // Because we are dealing with Value types we need not worry about what we return - } - - 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 - } -} +package Lecture1_adt; + +import org.jetbrains.annotations.NotNull; + +import java.util.Calendar; +//import java.util.Date; + +/** + * This Lecture1_adt.Transaction2 Class Takes the first step to resolves the ADT design issues of Transaction1: + * 1. Representation Independence: --- Encapsulation - Providing access methods to the internal data. + * External client code only access via allowable operations + * --- Changes to internal representation can still be accessed via same methods defined + * + * 2. Preservation of Invariants: --- Access Modifies private final makes the data Unchangeable + * + * Lecture1_adt + */ + +public class Transaction2 { + private final int amount; + private final Calendar date; + + public Transaction2(int amount, @NotNull Calendar date) { + this.amount = amount; + this.date = date; + } + + public int getAmount() { + return amount; // Because we are dealing with Value types we need not worry about what we return + } + + 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 + } +} diff --git a/src/Lecture1_adt/Transaction3.java b/src/Lecture1_adt/Transaction3.java index 48781e7..124c85d 100644 --- a/src/Lecture1_adt/Transaction3.java +++ b/src/Lecture1_adt/Transaction3.java @@ -1,31 +1,31 @@ -package Lecture1_adt; - -import org.jetbrains.annotations.NotNull; - -import java.util.Calendar; - -/** - * There is still Exposure seen in Transaction2 I that if we make next payment the date of first payment is also altered - * This Class Transaction3:Adds Code to correct this exposure: - * Intentional review of any methods that receive produces (returns) - * If produces interface of a method deals with objects or any reference types, - * there is need to perform defensive copying to enhance Invariant preservation - */ -public class Transaction3 { - private final int amount; - private final Calendar date; - - public Transaction3(int amount, @NotNull Calendar date) { - this.amount = amount; - this.date = date; - } - - public int getAmount() { - return amount; // Because we are dealing with Value types we need not worry about what we return - } - - 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 - } -} +package Lecture1_adt; + +import org.jetbrains.annotations.NotNull; + +import java.util.Calendar; + +/** + * There is still Exposure seen in Transaction2 I that if we make next payment the date of first payment is also altered + * This Class Transaction3:Adds Code to correct this exposure: + * Intentional review of any methods that receive produces (returns) + * If produces interface of a method deals with objects or any reference types, + * there is need to perform defensive copying to enhance Invariant preservation + */ +public class Transaction3 { + private final int amount; + private final Calendar date; + + public Transaction3(int amount, @NotNull Calendar date) { + this.amount = amount; + this.date = date; + } + + public int getAmount() { + return amount; // Because we are dealing with Value types we need not worry about what we return + } + + 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 + } +} diff --git a/src/Lecture1_adt/Transaction4.java b/src/Lecture1_adt/Transaction4.java index f09b0d8..e4fb3a2 100644 --- a/src/Lecture1_adt/Transaction4.java +++ b/src/Lecture1_adt/Transaction4.java @@ -1,32 +1,32 @@ -package Lecture1_adt; - -import org.jetbrains.annotations.NotNull; - -import java.util.Calendar; -/** - * There is still Exposure seen in Transaction3 in that if we make a list of 12 payments, - * the date of all payments remain the same. - * This Class Transaction4:Adds Code to correct this exposure: - * In Making th List of 12 Transactions, we are constantly using the constructor which takes a Date Object - * Intentional review of any methods that receives or requires (i.e. takes in as parameters) - * If requires interface of a method deals with objects or any reference types, - * there is need to perform defensive copying to enhance Invariant preservation - */ -public class Transaction4 { - private final int amount; - private final Calendar date; - - public Transaction4(int amount, @NotNull Calendar date) { - this.amount = amount; - this.date = (Calendar) date.clone(); // Defensive copying or Judicious Copying for Requires interfaces - } - - public int getAmount() { - return amount; // Because we are dealing with Value types we need not worry about what we return - } - - 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 for produces Interfaces - } -} +package Lecture1_adt; + +import org.jetbrains.annotations.NotNull; + +import java.util.Calendar; +/** + * There is still Exposure seen in Transaction3 in that if we make a list of 12 payments, + * the date of all payments remain the same. + * This Class Transaction4:Adds Code to correct this exposure: + * In Making th List of 12 Transactions, we are constantly using the constructor which takes a Date Object + * Intentional review of any methods that receives or requires (i.e. takes in as parameters) + * If requires interface of a method deals with objects or any reference types, + * there is need to perform defensive copying to enhance Invariant preservation + */ +public class Transaction4 { + private final int amount; + private final Calendar date; + + public Transaction4(int amount, @NotNull Calendar date) { + this.amount = amount; + this.date = (Calendar) date.clone(); // Defensive copying or Judicious Copying for Requires interfaces + } + + public int getAmount() { + return amount; // Because we are dealing with Value types we need not worry about what we return + } + + 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 for produces Interfaces + } +} diff --git a/src/Lecture2_adt_specification/Transaction4.java b/src/Lecture2_adt_specification/Transaction4.java index be8a1eb..49f242b 100644 --- a/src/Lecture2_adt_specification/Transaction4.java +++ b/src/Lecture2_adt_specification/Transaction4.java @@ -1,47 +1,47 @@ -package Lecture2_adt_specification; - -import org.jetbrains.annotations.NotNull; - -import java.util.Calendar; -//import java.util.Date; - -/** - * In Addition to the Design considerations in Transaction4 class: - * This class adds Specifications defining the Requires and Produces interfaces - */ - -public class Transaction4 { - private final int amount; - private final Calendar date; - - /** - * 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 Transaction4(int amount, @NotNull Calendar date) { - this.amount = amount; - this.date = (Calendar) date.clone(); - } - - - /** - * getAmount() - * @return integer - */ - public int getAmount() { - return amount; // Because we are dealing with Value types we need not worry about what we return - } - - /** - * 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 - } -} +package Lecture2_adt_specification; + +import org.jetbrains.annotations.NotNull; + +import java.util.Calendar; +//import java.util.Date; + +/** + * In Addition to the Design considerations in Transaction4 class: + * This class adds Specifications defining the Requires and Produces interfaces + */ + +public class Transaction4 { + private final int amount; + private final Calendar date; + + /** + * 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 Transaction4(int amount, @NotNull Calendar date) { + this.amount = amount; + this.date = (Calendar) date.clone(); + } + + + /** + * getAmount() + * @return integer + */ + public int getAmount() { + return amount; // Because we are dealing with Value types we need not worry about what we return + } + + /** + * 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 + } +} diff --git a/src/Lecture4_interfaces_abstract_classes/BankAccount.java b/src/Lecture4_interfaces_abstract_classes/BankAccount.java index 28d0d07..e69b32f 100644 --- a/src/Lecture4_interfaces_abstract_classes/BankAccount.java +++ b/src/Lecture4_interfaces_abstract_classes/BankAccount.java @@ -1,16 +1,37 @@ -package Lecture4_interfaces_abstract_classes; - -public class BankAccount { - private double balance; - public BankAccount(double balance) { - this.balance = balance; - } - - public double getBalance() { - return balance; - } - - public void setBalance(double balance) { - this.balance = balance; - } -} +package Lecture4_interfaces_abstract_classes; + +/** + * Represents a simple bank account with a balance. + * Starter code preserved; credit() and debit() helpers added + * so transaction classes don't need to call setBalance() directly. + */ +public class BankAccount { + private double balance; + + public BankAccount(double balance) { + this.balance = balance; + } + + public double getBalance() { + return balance; + } + + public void setBalance(double balance) { + this.balance = balance; + } + + /** Adds amount to the balance (used by DepositTransaction). */ + public void credit(double amount) { + this.balance += amount; + } + + /** Subtracts amount from the balance (used by WithdrawalTransaction). */ + public void debit(double amount) { + this.balance -= amount; + } + + @Override + public String toString() { + return String.format("BankAccount[Balance=%.2f]", balance); + } +} \ No newline at end of file diff --git a/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java b/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java index ed81eb8..ae26343 100644 --- a/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java +++ b/src/Lecture4_interfaces_abstract_classes/BaseTransaction.java @@ -1,51 +1,84 @@ -package Lecture4_interfaces_abstract_classes; - -import org.jetbrains.annotations.NotNull; - -import java.util.Calendar; - -public abstract 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 - */ - 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; - } - - /** - * getAmount() - * @return integer - */ - public double getAmount() { - return amount; // Because we are dealing with Value types we need not worry about what we return - } - - /** - * 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 - } - - // Method to get a unique identifier for the transaction - public String getTransactionID(){ - return transactionID; - } - // Method to print a transaction receipt or details - public abstract void printTransactionDetails(); - public abstract void apply(BankAccount ba); -} +package Lecture4_interfaces_abstract_classes; + +import org.jetbrains.annotations.NotNull; +import java.util.Calendar; + +/** + * Q1 - Concrete class that implements TransactionInterface. + * + * The starter code made this abstract; the assignment asks us to make it + * a CONCRETE class that fully implements the interface, while ensuring + * its apply() behaves differently from the subclasses. + * + * Fields match the starter code exactly (int amount, Calendar date, String transactionID). + */ +public class BaseTransaction implements TransactionInterface { + + // --- Fields (preserved from starter code) --- + private final int amount; + private final Calendar date; + private final String transactionID; + + /** + * Constructor - mirrors the starter code signature. + * + * @param amount integer transaction amount + * @param date must not be null; defensively copied to preserve invariants + */ + public BaseTransaction(int amount, @NotNull Calendar date) { + this.amount = amount; + this.date = (Calendar) date.clone(); // defensive copy (from lecture) + int uniq = (int)(Math.random() * 10000); + this.transactionID = date.toString() + uniq; + } + + // --------------------------------------------------------------- + // Q1 – Getter implementations (from TransactionInterface) + // --------------------------------------------------------------- + + @Override + public double getAmount() { + return amount; // int → double widening; value type, safe to return directly + } + + @Override + public Calendar getDate() { + return (Calendar) date.clone(); // defensive / judicious copy (from lecture) + } + + @Override + public String getTransactionID() { + return transactionID; + } + + // --------------------------------------------------------------- + // Q1 – printTransactionDetails() + // --------------------------------------------------------------- + + @Override + public void printTransactionDetails() { + System.out.println("=== Base Transaction Details ==="); + System.out.println(" Transaction ID : " + transactionID); + System.out.printf (" Amount : %.2f%n", (double) amount); + System.out.printf (" Date : %tF%n", date); + System.out.println(" Type : BaseTransaction"); + } + + // --------------------------------------------------------------- + // Q1 – apply() + // + // BaseTransaction.apply() is intentionally DIFFERENT from the + // subclass overrides: it is a neutral / informational application + // that logs the call but does NOT modify the account balance. + // This makes the base behaviour clearly distinct from Deposit + // (which credits) and Withdrawal (which debits). + // --------------------------------------------------------------- + + @Override + public void apply(BankAccount ba) { + System.out.printf( + "[BaseTransaction] apply() called — Amount: %.2f | Balance unchanged at: %.2f%n", + (double) amount, ba.getBalance() + ); + } +} \ No newline at end of file diff --git a/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java b/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java index 81afab5..bf93be9 100644 --- a/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java +++ b/src/Lecture4_interfaces_abstract_classes/DepositTrasaction.java @@ -1,30 +1,54 @@ -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); - } -} +package Lecture4_interfaces_abstract_classes; + +import org.jetbrains.annotations.NotNull; +import java.util.Calendar; + +/** + * Q1 & Q2 - Concrete class for deposit transactions. + * + * Deposits are IRREVERSIBLE by design (assignment spec, Q2). + * Overrides apply() to credit the BankAccount. + * + * Note: class name intentionally matches starter code spelling ("Trasaction"). + */ +public class DepositTrasaction extends BaseTransaction { + + // --- Constructor --- + public DepositTrasaction(int amount, @NotNull Calendar date) { + super(amount, date); + } + + // Helper preserved from starter code + private boolean checkDepositAmount(int amt) { + return amt >= 0; + } + + // --------------------------------------------------------------- + // Q1 – Override apply() + // Credits the account; clearly different from BaseTransaction.apply() + // which makes no balance change, and from WithdrawalTransaction + // which debits. + // --------------------------------------------------------------- + + @Override + public void apply(BankAccount ba) { + ba.credit(getAmount()); + System.out.printf( + "[DepositTransaction] Credited %.2f → New balance: %.2f%n", + getAmount(), ba.getBalance() + ); + } + + // --------------------------------------------------------------- + // Q1 – Override printTransactionDetails() + // --------------------------------------------------------------- + + @Override + public void printTransactionDetails() { + System.out.println("=== Deposit Transaction Details ==="); + System.out.println(" Transaction ID : " + getTransactionID()); + System.out.printf (" Amount : +%.2f%n", getAmount()); + System.out.printf (" Date : %tF%n", getDate()); + System.out.println(" Type : Deposit (irreversible)"); + } +} \ No newline at end of file diff --git a/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java b/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java new file mode 100644 index 0000000..ba2fd2c --- /dev/null +++ b/src/Lecture4_interfaces_abstract_classes/InsufficientFundsException.java @@ -0,0 +1,29 @@ +package Lecture4_interfaces_abstract_classes; + +/** + * Q3 - Custom checked exception for insufficient funds. + * + * Extends Exception (not RuntimeException) so it is a proper checked exception + * and callers are forced to handle or declare it — demonstrating Java's + * exception hierarchy through inheritance. + */ +public class InsufficientFundsException extends Exception { + + private final double amountRequested; + private final double amountAvailable; + + public InsufficientFundsException(double amountRequested, double amountAvailable) { + super(String.format( + "Insufficient funds: requested %.2f but only %.2f is available.", + amountRequested, amountAvailable + )); + this.amountRequested = amountRequested; + this.amountAvailable = amountAvailable; + } + + public double getAmountRequested() { return amountRequested; } + public double getAmountAvailable() { return amountAvailable; } + + /** Convenience: how much short the account is. */ + public double getShortfall() { return amountRequested - amountAvailable; } +} \ No newline at end of file diff --git a/src/Lecture4_interfaces_abstract_classes/TransactionInterface.java b/src/Lecture4_interfaces_abstract_classes/TransactionInterface.java index 5902713..2589993 100644 --- a/src/Lecture4_interfaces_abstract_classes/TransactionInterface.java +++ b/src/Lecture4_interfaces_abstract_classes/TransactionInterface.java @@ -1,21 +1,27 @@ -package Lecture4_interfaces_abstract_classes; -import java.util.Calendar; - -/** - * Interface for Transactions - * Any class that defines a transaction is expected to implement this Interface - */ -public interface TransactionInterface { - - // Method to get the transaction amount - double getAmount(); - - // Method to get the transaction date - Calendar getDate(); - - // Method to get a unique identifier for the transaction - String getTransactionID(); - -} - - +package Lecture4_interfaces_abstract_classes; + +import java.util.Calendar; + +/** + * Interface for Transactions. + * Any class that defines a transaction is expected to implement this interface. + * + * Q1: Extended with printTransactionDetails() and apply() as required by the assignment. + */ +public interface TransactionInterface { + + // Method to get the transaction amount + double getAmount(); + + // Method to get the transaction date + Calendar getDate(); + + // Method to get a unique identifier for the transaction + String getTransactionID(); + + // Method to print transaction details (Q1) + void printTransactionDetails(); + + // Method to apply the transaction to a BankAccount (Q1) + void apply(BankAccount ba); +} \ No newline at end of file diff --git a/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java b/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java index face5b6..0c0e31b 100644 --- a/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java +++ b/src/Lecture4_interfaces_abstract_classes/WithdrawalTransaction.java @@ -1,45 +1,163 @@ -package Lecture4_interfaces_abstract_classes; - -import org.jetbrains.annotations.NotNull; - -import java.util.Calendar; - -public class WithdrawalTransaction extends BaseTransaction { - public WithdrawalTransaction(int amount, @NotNull Calendar date) { - super(amount, date); - } - - private boolean checkDepositAmount(int amt) { - if (amt < 0) { - return false; - } else { - return true; - } - } - - // Method to reverse the transaction - public boolean reverse() { - 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()); - } - - /* - 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); - } - } - - /* - Assignment 1 Q3: Write the Reverse method - a method unique to the WithdrawalTransaction Class - */ -} - +package Lecture4_interfaces_abstract_classes; + +import org.jetbrains.annotations.NotNull; +import java.util.Calendar; + +/** + * Q1, Q2 & Q3 - Concrete class for withdrawal transactions. + * + * Withdrawals are REVERSIBLE by design (assignment spec, Q2). + * + * Q1 – Overrides apply() to debit the BankAccount. + * Q2 – Implements reverse() to restore the account to its pre-withdrawal balance. + * Q3 – Overloaded apply(BankAccount, boolean) uses the 'throws' keyword and a + * try { } catch { } finally { } block; handles the partial-withdrawal case. + */ +public class WithdrawalTransaction extends BaseTransaction { + + // Tracks the account this transaction was applied to (needed for reverse()) + private BankAccount appliedAccount = null; + + // Records any amount that could NOT be withdrawn in a partial withdrawal + private double amountNotWithdrawn = 0.0; + + // Guards against reversing a transaction that was never successfully applied + private boolean isApplied = false; + + // --- Constructor (matches starter code signature) --- + public WithdrawalTransaction(int amount, @NotNull Calendar date) { + super(amount, date); + } + + // Helper preserved from starter code + private boolean checkDepositAmount(int amt) { + return amt >= 0; + } + + // --------------------------------------------------------------- + // Q1 – Override apply() + // + // Simple debit; delegates to the overloaded version. + // Any InsufficientFundsException is caught here and reported so + // that this override still satisfies the void / no-throws signature + // required by the interface. + // --------------------------------------------------------------- + + @Override + public void apply(BankAccount ba) { + try { + apply(ba, false); + } catch (InsufficientFundsException e) { + System.err.println("[WithdrawalTransaction] apply() blocked: " + e.getMessage()); + } + } + + // --------------------------------------------------------------- + // Q3 – Overloaded apply() with full exception handling + // + // @param ba the account to debit + // @param allowPartial if true: when 0 < balance < amount, withdraw + // all available balance and record the shortfall. + // if false: throw InsufficientFundsException. + // + // Uses: throws keyword (method signature) + // try / catch / finally block (inside the method body) + // --------------------------------------------------------------- + + public void apply(BankAccount ba, boolean allowPartial) throws InsufficientFundsException { + + try { + double balance = ba.getBalance(); + + // Case A: account is empty or overdrawn + if (balance <= 0) { + throw new InsufficientFundsException(getAmount(), balance); + } + + // Case B: partial withdrawal allowed and 0 < balance < amount + if (allowPartial && balance < getAmount()) { + amountNotWithdrawn = getAmount() - balance; + ba.debit(balance); // withdraw everything available + appliedAccount = ba; + isApplied = true; + + System.out.printf( + "[WithdrawalTransaction] Partial withdrawal: debited %.2f. " + + "Amount not withdrawn: %.2f. New balance: %.2f%n", + balance, amountNotWithdrawn, ba.getBalance() + ); + + } else if (balance < getAmount()) { + // Case C: insufficient funds, partial NOT allowed → throw + throw new InsufficientFundsException(getAmount(), balance); + + } else { + // Case D: sufficient funds → normal full debit + ba.debit(getAmount()); + appliedAccount = ba; + isApplied = true; + + System.out.printf( + "[WithdrawalTransaction] Debited %.2f. New balance: %.2f%n", + getAmount(), ba.getBalance() + ); + } + + } catch (InsufficientFundsException e) { + // Log and re-throw so the caller can decide how to handle it + System.err.println("[WithdrawalTransaction] Caught: " + e.getMessage()); + throw e; + + } finally { + // Always runs — suitable for audit/logging regardless of outcome + System.out.println("[WithdrawalTransaction] apply() finished for account balance: " + + ba.getBalance()); + } + } + + // --------------------------------------------------------------- + // Q2 – reverse() + // + // Reverses a previously applied withdrawal by crediting the exact + // amount that was debited back to the original BankAccount. + // Returns true on success, false if the transaction was never applied. + // --------------------------------------------------------------- + + public boolean reverse() { + if (!isApplied || appliedAccount == null) { + System.out.println("[WithdrawalTransaction] reverse() failed: transaction not yet applied."); + return false; + } + + // Amount actually debited = requested amount minus whatever was not withdrawn + double actuallyDebited = getAmount() - amountNotWithdrawn; + appliedAccount.credit(actuallyDebited); + + System.out.printf( + "[WithdrawalTransaction] Reversed: credited %.2f back. Restored balance: %.2f%n", + actuallyDebited, appliedAccount.getBalance() + ); + + // Reset state so the transaction cannot be reversed twice + isApplied = false; + appliedAccount = null; + + return true; + } + + // --------------------------------------------------------------- + // Q1 – Override printTransactionDetails() + // --------------------------------------------------------------- + + @Override + public void printTransactionDetails() { + System.out.println("=== Withdrawal Transaction Details ==="); + System.out.println(" Transaction ID : " + getTransactionID()); + System.out.printf (" Amount : -%.2f%n", getAmount()); + System.out.printf (" Date : %tF%n", getDate()); + System.out.printf (" Amount Not Withdrawn : %.2f%n", amountNotWithdrawn); + System.out.println(" Type : Withdrawal (reversible)"); + } + + public double getAmountNotWithdrawn() { return amountNotWithdrawn; } +} \ No newline at end of file diff --git a/src/Main.java b/src/Main.java index 584a048..e1bb8e3 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,156 +1,237 @@ -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() - } +import Lecture1_adt.*; +import Lecture4_interfaces_abstract_classes.*; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.ArrayList; +import java.util.List; + +/** + * Client Code - Main class. + * + * Existing lecture test functions are preserved unchanged. + * Q4 adds testDepositTransaction(), testWithdrawalTransaction(), + * and testPolymorphism() below. + */ +public class Main { + + // ================================================================ + // Existing lecture test functions (unchanged) + // ================================================================ + + public static void testTransaction1() { + Calendar d1 = new GregorianCalendar(); + Lecture1_adt.Transaction1 t1 = new Lecture1_adt.Transaction1(1000, d1); + + 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); + } + + public static Transaction2 makeNextPayment(Transaction2 t) { + Calendar d = t.getDate(); + d.add(Calendar.MONTH, 1); + return new Transaction2(t.getAmount(), d); + } + + 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()); + } + + 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; + } + + public static void testTransaction3() { + List allPaymentsIn2024 = makeYearOfPayments(1000); + for (Transaction3 t3 : allPaymentsIn2024) { + 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()); + } + } + } + + 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; + } + + public static void testTransaction4() { + List transactionsIn2024 = makeYearOfPaymentsFinal(1200); + 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()); + } + } + + + // ================================================================ + // Q4 – New client code: DepositTransaction tests + // ================================================================ + + public static void testDepositTransaction() { + System.out.println("\n============================================================"); + System.out.println(" TEST: DepositTransaction"); + System.out.println("============================================================"); + + Calendar date = new GregorianCalendar(); + BankAccount account = new BankAccount(500.00); + System.out.println("Initial balance: " + account.getBalance()); + + // --- Subtype object, subtype reference --- + DepositTrasaction deposit = new DepositTrasaction(200, date); + deposit.printTransactionDetails(); + deposit.apply(account); + System.out.println("Balance after deposit: " + account.getBalance()); + + // --- Type-cast subtype to supertype, then call apply() --- + // The reference is BaseTransaction (supertype), object is DepositTrasaction. + // Java resolves apply() at RUNTIME (late binding / dynamic dispatch), + // so DepositTrasaction.apply() is called — not BaseTransaction.apply(). + System.out.println("\n-- Type-casting DepositTrasaction → BaseTransaction --"); + BaseTransaction castedDeposit = (BaseTransaction) new DepositTrasaction(100, date); + castedDeposit.printTransactionDetails(); + castedDeposit.apply(account); // late binding → DepositTrasaction.apply() + System.out.println("Balance after casted deposit: " + account.getBalance()); + } + + + // ================================================================ + // Q4 – New client code: WithdrawalTransaction tests + // ================================================================ + + public static void testWithdrawalTransaction() { + System.out.println("\n============================================================"); + System.out.println(" TEST: WithdrawalTransaction"); + System.out.println("============================================================"); + + Calendar date = new GregorianCalendar(); + BankAccount account = new BankAccount(1000.00); + System.out.println("Initial balance: " + account.getBalance()); + + // --- Normal withdrawal (sufficient funds) --- + WithdrawalTransaction w1 = new WithdrawalTransaction(300, date); + w1.printTransactionDetails(); + w1.apply(account); + System.out.println("Balance after withdrawal: " + account.getBalance()); + + // --- Reverse the withdrawal (Q2) --- + System.out.println("\n-- Reversing withdrawal --"); + boolean reversed = w1.reverse(); + System.out.println("Reversal successful: " + reversed); + System.out.println("Balance after reversal: " + account.getBalance()); + + // --- Insufficient funds, allowPartial = false (Q3, throws) --- + System.out.println("\n-- Withdrawal exceeding balance (allowPartial=false) --"); + WithdrawalTransaction w2 = new WithdrawalTransaction(9999, date); + try { + w2.apply(account, false); + } catch (InsufficientFundsException e) { + System.out.println("Caught InsufficientFundsException: " + e.getMessage()); + System.out.printf ("Shortfall: %.2f%n", e.getShortfall()); + } + System.out.println("Balance unchanged: " + account.getBalance()); + + // --- Partial withdrawal: 0 < balance < amount (Q3) --- + System.out.println("\n-- Partial withdrawal (allowPartial=true, balance < amount) --"); + BankAccount smallAccount = new BankAccount(80.00); + WithdrawalTransaction w3 = new WithdrawalTransaction(200, date); + try { + w3.apply(smallAccount, true); + } catch (InsufficientFundsException e) { + System.err.println("Unexpected exception: " + e.getMessage()); + } + w3.printTransactionDetails(); + System.out.println("Balance after partial withdrawal: " + smallAccount.getBalance()); + } + + + // ================================================================ + // Q4 – New client code: Polymorphism (early vs. late binding) + // ================================================================ + + public static void testPolymorphism() { + System.out.println("\n============================================================"); + System.out.println(" TEST: Polymorphism — Early vs. Late Binding"); + System.out.println("============================================================"); + + Calendar date = new GregorianCalendar(); + BankAccount account = new BankAccount(500.00); + + /* + * EARLY BINDING (compile-time / static dispatch): + * The reference type AND the object type are both BaseTransaction. + * The compiler resolves apply() to BaseTransaction.apply() at + * compile time because there is no subtype to dispatch to. + * Result: no balance change (BaseTransaction.apply() is informational). + */ + System.out.println("-- Early Binding: BaseTransaction reference, BaseTransaction object --"); + BaseTransaction earlyBound = new BaseTransaction(50, date); + earlyBound.apply(account); + System.out.println("Balance (unchanged): " + account.getBalance()); + + /* + * LATE BINDING (runtime / dynamic dispatch): + * The reference type is BaseTransaction (supertype), but the actual + * object at runtime is DepositTrasaction (subtype). + * The JVM looks up the method in the actual object's class at runtime + * and dispatches to DepositTrasaction.apply() → balance increases. + */ + System.out.println("\n-- Late Binding: BaseTransaction reference, DepositTrasaction object --"); + BaseTransaction lateDeposit = new DepositTrasaction(150, date); + lateDeposit.apply(account); // JVM dispatches to DepositTrasaction.apply() + System.out.println("Balance after late-bound deposit: " + account.getBalance()); + + /* + * LATE BINDING with WithdrawalTransaction: + * Same principle — the supertype reference holds a WithdrawalTransaction. + * apply() resolves to WithdrawalTransaction.apply() at runtime. + */ + System.out.println("\n-- Late Binding: BaseTransaction reference, WithdrawalTransaction object --"); + BaseTransaction lateWithdraw = new WithdrawalTransaction(100, date); + lateWithdraw.apply(account); // JVM dispatches to WithdrawalTransaction.apply() + System.out.println("Balance after late-bound withdrawal: " + account.getBalance()); + } + + + // ================================================================ + // main() + // ================================================================ + + public static void main(String[] args) { + // Existing lecture tests (uncomment as needed) + // testTransaction1(); + // testTransaction2(); + // testTransaction3(); + // testTransaction4(); + + // Q4 – Assignment tests + testDepositTransaction(); + testWithdrawalTransaction(); + testPolymorphism(); + } } \ No newline at end of file