This example models a Banking System where an Account
class uses composition to interact with a TransactionLogger
class.
import java.util.ArrayList;
import java.util.List;
// Class to handle transaction logging (Composition)
class TransactionLogger {
private List<String> transactionHistory = new ArrayList<>();
// Method to log transactions
public void logTransaction(String transaction) {
transactionHistory.add(transaction);
}
// Method to display transaction history
public void displayTransactions() {
System.out.println("Transaction History:");
for (String transaction : transactionHistory) {
System.out.println(transaction);
}
}
}
// Class representing a Bank Account
class BankAccount {
private String accountHolder;
private double balance;
private TransactionLogger logger; // Composition: Using another class
// Constructor to initialize account
public BankAccount(String accountHolder, double initialDeposit) {
this.accountHolder = accountHolder;
this.balance = initialDeposit;
this.logger = new TransactionLogger(); // Creating logger instance
logger.logTransaction("Account created with initial deposit: $" + initialDeposit);
}
// Method to deposit money
public void deposit(double amount) {
balance += amount;
logger.logTransaction("Deposited: $" + amount);
}
// Method to withdraw money
public boolean withdraw(double amount) {
if (amount > balance) {
logger.logTransaction("Failed withdrawal attempt: Insufficient funds.");
return false;
}
balance -= amount;
logger.logTransaction("Withdrawn: $" + amount);
return true;
}
// Method to display account balance
public void displayBalance() {
System.out.println(accountHolder + "'s Balance: $" + balance);
}
// Method to show transaction history
public void displayTransactionHistory() {
logger.displayTransactions();
}
}
// Main class
public class BankingSystem {
public static void main(String[] args) {
// Creating a bank account
BankAccount account = new BankAccount("Alice Johnson", 1000.0);
// Performing transactions
account.deposit(500.0);
account.withdraw(300.0);
account.withdraw(1500.0); // Should fail due to insufficient funds
// Displaying balance and transaction history
account.displayBalance();
account.displayTransactionHistory();
}
}
Alice Johnson's Balance: $1200.0
Transaction History:
Account created with initial deposit: $1000.0
Deposited: $500.0
Withdrawn: $300.0
Failed withdrawal attempt: Insufficient funds.
BankAccount
class keeps balance
private.TransactionLogger
instance, ensuring controlled access.BankAccount
contains an instance of TransactionLogger
(has-a relationship).BankAccount
delegates logging responsibility to TransactionLogger
.TransactionLogger
abstracts logging logic, making it reusable for different classes (e.g., future SavingsAccount, LoanAccount).✅ Encapsulation – Prevents direct access to sensitive data.
✅ Composition over Inheritance – More flexible and modular than rigid inheritance hierarchies.
✅ Separation of Concerns – The banking logic and transaction history are managed independently, making the code cleaner and more maintainable.
This Java example demonstrates advanced object-oriented design with a real-world banking system, ensuring scalability and maintainability.