Banking Account Management System
Inheritance hierarchy for different bank account types with client management
classDiagram
class Account {
<<abstract>>
-int id
#float balance
-int$ accountCountno no
+Account(float balance)
+deposit(float amount) void
+withdraw(float amount)* void
+getBalance() float
}
class SimpleAccount {
-float overdraft
+SimpleAccount(float balance, float overdraft)
+withdraw(float amount) void
}
class WithdrawalException {
<<exception>>
+WithdrawalException(String message)
}
class SavingsAccount {
-float interestRate
+SavingsAccount(float rate, float balance)
+calculateInterest() void
}
class Client {
-int id
-int$ clientCount
-String firstName
-String lastName
-List~Account~ accounts
+Client(String firstName, String lastName)
+calculateTotalAssets() float
+add(Account account) void
}
class FeeAccount {
-float fee
+FeeAccount(float balance, float fee)
+deposit(float amount) void
+withdraw(float amount) void
}
class OverdraftException {
<<exception>>
+OverdraftException(String message)
}
SimpleAccount --|> Account
SavingsAccount --|> Account
FeeAccount --|> Account
Client "1" --> "0..*" Account
Account (Abstract Base Class)
Section titled “Account (Abstract Base Class)”The parent abstract class for all bank account types.
- id: Unique account identifier (private)
- balance: Current account balance (protected - accessible to subclasses)
- accountCount: Static counter for total accounts created (private, shared across all instances)
- Account(float balance): Constructor to initialize account with starting balance, auto-increments accountCount
- deposit(float amount): Add money to the account
- withdraw(float amount): Abstract method - must be implemented by subclasses
- getBalance(): Returns current balance
- Protected balance allows subclasses to access and modify the balance
- Cannot be instantiated directly
SimpleAccount
Section titled “SimpleAccount”Standard checking account with overdraft protection.
- overdraft: Maximum overdraft limit allowed (private)
- SimpleAccount(float balance, float overdraft): Constructor with initial balance and overdraft limit
- Inherits from
Account - Overrides withdraw(): Allows withdrawal up to balance + overdraft limit
- Throws OverdraftException if withdrawal exceeds available funds + overdraft
SavingsAccount
Section titled “SavingsAccount”Interest-bearing savings account.
- interestRate: Annual interest rate as percentage (private)
- SavingsAccount(float rate, float balance): Constructor with interest rate and initial balance
- Inherits from
Account - calculateInterest(): Calculates and adds interest to balance based on interestRate
- Cannot withdraw if balance would go negative (no overdraft allowed)
FeeAccount
Section titled “FeeAccount”Account that charges fees for transactions.
- fee: Fixed fee charged per transaction (private)
- FeeAccount(float balance, float fee): Constructor with initial balance and fee amount
- Inherits from
Account - Overrides deposit(): Charges fee for each deposit transaction
- Overrides withdraw(): Charges fee for each withdrawal transaction
- Useful for premium accounts with additional services
Client
Section titled “Client”Bank client that can own multiple accounts.
- id: Unique client identifier (private)
- clientCount: Static counter for total clients created (private, shared across all instances)
- firstName: Client’s first name (private)
- lastName: Client’s last name (private)
- accounts: List of accounts owned by this client (private
List<Account>) - Client(String firstName, String lastName): Constructor that auto-increments clientCount
- calculateTotalAssets(): Sum of balances across all client accounts
- add(Account account): Associate a new account with this client
- One client can have zero or more accounts (one-to-many relationship)
WithdrawalException
Section titled “WithdrawalException”Exception thrown when withdrawal fails.
- Thrown when attempting to withdraw more than available balance
- Extends Exception class
- Used by
Accountand its subclasses
OverdraftException
Section titled “OverdraftException”Exception thrown when overdraft limit exceeded.
- Thrown by SimpleAccount when withdrawal exceeds balance + overdraft limit
- Specialized exception for overdraft scenarios
- Extends Exception class
Practice Exercise: Implement the Banking System
Section titled “Practice Exercise: Implement the Banking System”Objective: Implement the complete banking system with abstract base class, static counters, and exception handling.
Requirements:
- Create the abstract
Accountbase class with static counter and abstract withdraw() - Implement all three account types (SimpleAccount, SavingsAccount, FeeAccount)
- Create custom exception classes
- Implement Client class with static counter and account management
- Demonstrate polymorphism by storing different account types in Client
💡 Click to see suggested implementation
// Custom Exceptionspublic class WithdrawalException extends Exception { public WithdrawalException(String message) { super(message); }}
public class OverdraftException extends Exception { public OverdraftException(String message) { super(message); }}
// Abstract base classpublic abstract class Account { private static int accountCount = 0; // Static counter private int id; protected float balance;
public Account(float balance) { this.balance = balance; this.id = ++accountCount; // Auto-increment ID }
public void deposit(float amount) { if (amount > 0) { balance += amount; System.out.println("Deposited: $" + amount + " | New balance: $" + balance); } }
// Abstract method - must be implemented by subclasses public abstract void withdraw(float amount) throws WithdrawalException, OverdraftException;
public float getBalance() { return balance; } public int getId() { return id; } public static int getAccountCount() { return accountCount; }}
// SimpleAccount classpublic class SimpleAccount extends Account { private float overdraft;
public SimpleAccount(float balance, float overdraft) { super(balance); this.overdraft = overdraft; }
@Override public void withdraw(float amount) throws OverdraftException { if (amount > balance + overdraft) { throw new OverdraftException("Insufficient funds! Max withdrawal: $" + (balance + overdraft)); } balance -= amount; System.out.println("Withdrawn: $" + amount + " | New balance: $" + balance); }
public float getOverdraft() { return overdraft; }}
// SavingsAccount classpublic class SavingsAccount extends Account { private float interestRate;
public SavingsAccount(float rate, float balance) { super(balance); this.interestRate = rate; }
@Override public void withdraw(float amount) throws WithdrawalException { if (amount > balance) { throw new WithdrawalException("Insufficient funds! Balance: $" + balance); } balance -= amount; System.out.println("Withdrawn: $" + amount + " | New balance: $" + balance); }
public void calculateInterest() { float interest = balance * (interestRate / 100); balance += interest; System.out.println("Interest added: $" + interest + " | New balance: $" + balance); }
public float getInterestRate() { return interestRate; }}
// FeeAccount classpublic class FeeAccount extends Account { private float fee;
public FeeAccount(float balance, float fee) { super(balance); this.fee = fee; }
@Override public void deposit(float amount) { balance += amount - fee; // Charge fee on deposit System.out.println("Deposited: $" + amount + " (Fee: $" + fee + ") | New balance: $" + balance); }
@Override public void withdraw(float amount) throws WithdrawalException { float totalAmount = amount + fee; if (totalAmount > balance) { throw new WithdrawalException("Insufficient funds including fee! Required: $" + totalAmount); } balance -= totalAmount; System.out.println("Withdrawn: $" + amount + " (Fee: $" + fee + ") | New balance: $" + balance); }
public float getFee() { return fee; }}
// Client classimport java.util.ArrayList;import java.util.List;
public class Client { private static int clientCount = 0; // Static counter private int id; private String firstName; private String lastName; private List<Account> accounts;
public Client(String firstName, String lastName) { this.id = ++clientCount; // Auto-increment ID this.firstName = firstName; this.lastName = lastName; this.accounts = new ArrayList<>(); }
public void add(Account account) { accounts.add(account); System.out.println("Account #" + account.getId() + " added to " + firstName + " " + lastName); }
public float calculateTotalAssets() { float total = 0; for (Account account : accounts) { total += account.getBalance(); } return total; }
public String getName() { return firstName + " " + lastName; } public int getId() { return id; } public static int getClientCount() { return clientCount; } public List<Account> getAccounts() { return accounts; }}
// Example usagepublic class BankingDemo { public static void main(String[] args) { System.out.println("=== Banking System Demo ===\n");
// Create clients Client client1 = new Client("John", "Doe"); Client client2 = new Client("Jane", "Smith");
// Create different types of accounts SimpleAccount checking = new SimpleAccount(1000, 500); // $1000 balance, $500 overdraft SavingsAccount savings = new SavingsAccount(3.5f, 5000); // 3.5% interest, $5000 balance FeeAccount premium = new FeeAccount(10000, 2); // $10000 balance, $2 fee per transaction
// Add accounts to clients client1.add(checking); client1.add(savings); client2.add(premium);
System.out.println("\nTotal accounts created: " + Account.getAccountCount()); System.out.println("Total clients created: " + Client.getClientCount());
// Perform transactions try { System.out.println("\n=== Simple Account Operations ==="); checking.deposit(200); checking.withdraw(800);
System.out.println("\n=== Savings Account Operations ==="); savings.calculateInterest(); savings.withdraw(500);
System.out.println("\n=== Fee Account Operations ==="); premium.deposit(100); // Will charge fee premium.withdraw(50); // Will charge fee
System.out.println("\n=== Client Total Assets ==="); System.out.println(client1.getName() + " total assets: $" + client1.calculateTotalAssets()); System.out.println(client2.getName() + " total assets: $" + client2.calculateTotalAssets());
// Test overdraft exception System.out.println("\n=== Testing Overdraft Exception ==="); checking.withdraw(2000); // Should throw exception
} catch (OverdraftException e) { System.err.println("Overdraft Error: " + e.getMessage()); } catch (WithdrawalException e) { System.err.println("Withdrawal Error: " + e.getMessage()); } }}Key Implementation Points:
- Use
statickeyword for accountCount and clientCount (use$in Mermaid) - Static variables are shared across all instances of the class
- Use
abstractkeyword for Account class and withdraw() method - All subclasses MUST implement abstract withdraw() method
- Use
@Overrideannotation when overriding methods - Call
super(balance)in subclass constructors - Exceptions extend Exception class and are thrown/caught appropriately
- Use
++prefix increment for auto-incrementing static counters

