Build a banking system that demonstrates inheritance, polymorphism, abstract classes, and encapsulation. Create different account types with specialized behaviors.
Requirements
Create an abstract base classBankAccount with account number, balance, and abstract methods
Implement SavingsAccount with interest rate and minimum balance
Implement CheckingAccount with overdraft limit and transaction fees
Implement BusinessAccount with higher limits and business features
Create a Bank class that manages multiple accounts
Support deposit, withdraw, and transfer operations with proper validation
Display account summaries with formatted output
Expected Output
Terminal
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā BANK ACCOUNT SYSTEM ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
š¦ Creating accounts...
ā Savings Account Created: SA-001 | Balance: $1,000.00
ā Checking Account Created: CA-001 | Balance: $500.00
ā Business Account Created: BA-001 | Balance: $10,000.00
š Account Summary:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
SA-001 [Savings] | $1,000.00 | Rate: 2.5%
CA-001 [Checking] | $500.00 | Overdraft: $200.00
BA-001 [Business] | $10,000.00| Limit: $50,000.00
š° Transactions:
ā Depositing $200.00 to SA-001: ā New balance: $1,200.00
ā Withdrawing $600.00 from CA-001: ā New balance: -$100.00 (overdraft)
ā Transferring $2,000.00 from BA-001 to SA-001: ā Complete
š Final Balances:
SA-001: $3,200.00 (+$2,200.00)
CA-001: -$100.00 (-$600.00)
BA-001: $8,000.00 (-$2,000.00)
import 'dart:math';
// Step 1: Abstract base class
abstract class BankAccount {
final String accountNumber;
double _balance;
final DateTime createdAt;
BankAccount(this.accountNumber, double initialBalance)
: _balance = initialBalance,
createdAt = DateTime.now();
// Encapsulated balance with getter
double get balance => _balance;
// Abstract methods - must be implemented by subclasses
String get accountType;
double get monthlyFee;
String get displayInfo;
// Concrete methods
bool deposit(double amount) {
if (amount <= 0) {
print('ā Deposit amount must be positive.');
return false;
}
_balance += amount;
print('ā Deposited \$${amount.toStringAsFixed(2)} to $accountNumber');
return true;
}
bool withdraw(double amount) {
if (amount <= 0) {
print('ā Withdrawal amount must be positive.');
return false;
}
if (!canWithdraw(amount)) {
print('ā Insufficient funds or limit exceeded.');
return false;
}
_balance -= amount;
print('ā Withdrew \$${amount.toStringAsFixed(2)} from $accountNumber');
return true;
}
// Protected method for subclasses to override
bool canWithdraw(double amount) => _balance >= amount;
@override
String toString() => '$accountNumber [$accountType] | \$${_balance.toStringAsFixed(2)}';
}
// Step 2: Savings Account
class SavingsAccount extends BankAccount {
final double interestRate;
final double minimumBalance;
SavingsAccount(String accountNumber, double initialBalance, {
this.interestRate = 0.025,
this.minimumBalance = 100.0,
}) : super(accountNumber, initialBalance);
@override
String get accountType => 'Savings';
@override
double get monthlyFee => 0.0; // No monthly fee
@override
String get displayInfo => 'Rate: ${(interestRate * 100).toStringAsFixed(1)}%';
@override
bool canWithdraw(double amount) {
return (balance - amount) >= minimumBalance;
}
void applyInterest() {
double interest = balance * interestRate / 12;
deposit(interest);
print(' Interest applied: +\$${interest.toStringAsFixed(2)}');
}
}
// Step 3: Checking Account
class CheckingAccount extends BankAccount {
final double overdraftLimit;
int _transactionsThisMonth = 0;
static const double transactionFee = 1.50;
static const int freeTransactions = 10;
CheckingAccount(String accountNumber, double initialBalance, {
this.overdraftLimit = 200.0,
}) : super(accountNumber, initialBalance);
@override
String get accountType => 'Checking';
@override
double get monthlyFee => _transactionsThisMonth > freeTransactions
? (_transactionsThisMonth - freeTransactions) * transactionFee
: 0.0;
@override
String get displayInfo => 'Overdraft: \$${overdraftLimit.toStringAsFixed(2)}';
@override
bool canWithdraw(double amount) {
return (balance - amount) >= -overdraftLimit;
}
@override
bool withdraw(double amount) {
if (super.withdraw(amount)) {
_transactionsThisMonth++;
return true;
}
return false;
}
}
// Step 4: Business Account
class BusinessAccount extends BankAccount {
final double creditLimit;
final String businessName;
final List authorizedSigners;
BusinessAccount(
String accountNumber,
double initialBalance,
this.businessName, {
this.creditLimit = 50000.0,
List? signers,
}) : authorizedSigners = signers ?? [],
super(accountNumber, initialBalance);
@override
String get accountType => 'Business';
@override
double get monthlyFee => 25.0;
@override
String get displayInfo => 'Limit: \$${creditLimit.toStringAsFixed(2)} | $businessName';
@override
bool canWithdraw(double amount) {
return (balance - amount) >= -creditLimit;
}
void addAuthorizedSigner(String name) {
authorizedSigners.add(name);
print('ā Added signer: $name');
}
}
// Step 5: Bank class to manage accounts
class Bank {
final String name;
final List _accounts = [];
Bank(this.name);
void addAccount(BankAccount account) {
_accounts.add(account);
print('ā ${account.accountType} Account Created: ${account.accountNumber} | Balance: \$${account.balance.toStringAsFixed(2)}');
}
BankAccount? findAccount(String accountNumber) {
try {
return _accounts.firstWhere((a) => a.accountNumber == accountNumber);
} catch (e) {
return null;
}
}
bool transfer(String fromAcc, String toAcc, double amount) {
final from = findAccount(fromAcc);
final to = findAccount(toAcc);
if (from == null || to == null) {
print('ā Account not found.');
return false;
}
if (from.withdraw(amount)) {
to.deposit(amount);
print('ā Transfer: \$${amount.toStringAsFixed(2)} from $fromAcc to $toAcc');
return true;
}
return false;
}
void displayAllAccounts() {
print('\nš Account Summary:');
print('ā' * 50);
for (var account in _accounts) {
print('$account | ${account.displayInfo}');
}
}
double get totalDeposits => _accounts.fold(0, (sum, acc) => sum + acc.balance);
}
// Step 6: Main program
void main() {
print('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
print('ā BANK ACCOUNT SYSTEM ā');
print('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
final bank = Bank('Dart National Bank');
// Create accounts
print('š¦ Creating accounts...\n');
final savings = SavingsAccount('SA-001', 1000.0);
final checking = CheckingAccount('CA-001', 500.0);
final business = BusinessAccount('BA-001', 10000.0, 'Tech Corp Inc.');
bank.addAccount(savings);
bank.addAccount(checking);
bank.addAccount(business);
// Display summary
bank.displayAllAccounts();
// Perform transactions
print('\nš° Transactions:');
savings.deposit(200.0);
checking.withdraw(600.0); // Goes into overdraft
bank.transfer('BA-001', 'SA-001', 2000.0);
// Apply interest to savings
print('\nš¹ Applying monthly interest...');
savings.applyInterest();
// Final summary
print('\nš Final Balances:');
for (var account in bank._accounts) {
double change = account.balance - (account == savings ? 1000.0 : account == checking ? 500.0 : 10000.0);
String sign = change >= 0 ? '+' : '';
print('${account.accountNumber}: \$${account.balance.toStringAsFixed(2)} (${sign}\$${change.toStringAsFixed(2)})');
}
print('\nš¦ Total Bank Deposits: \$${bank.totalDeposits.toStringAsFixed(2)}');
}