引言:构建完整的银行系统

在前面的章节中,我们学习了Python面向对象编程的各个方面,包括类与对象、继承与多态、魔术方法、异常处理等。现在,我们将综合运用这些知识,构建一个完整的面向对象银行账户管理系统。

本项目将实现一个支持多种账户类型的银行系统,包括储蓄账户、支票账户和高级账户,每种账户类型都有其特定的行为和规则。我们将使用继承来实现代码复用,使用多态来处理不同类型的账户,使用异常处理来确保系统的健壮性。


第一部分:项目需求分析

1.1 功能需求

我们的银行账户管理系统需要支持以下功能:

  1. 账户管理

    • 创建不同类型的账户(储蓄账户、支票账户、高级账户)
    • 删除账户
    • 查询账户信息
    • 修改账户属性
  2. 交易功能

    • 存款
    • 取款
    • 转账
    • 计算利息
  3. 账户特性

    • 储蓄账户:最低余额要求,固定利率
    • 支票账户:透支额度,交易手续费
    • 高级账户:更高利率,奖励积分,免手续费
  4. 系统管理

    • 用户认证
    • 交易记录
    • 账户统计
    • 系统配置

1.2 技术需求

我们将使用以下Python特性实现系统:

  1. 类和对象
  2. 继承和多态
  3. 抽象基类和接口
  4. 魔术方法
  5. 异常处理
  6. 模块和包
  7. 装饰器
  8. 上下文管理器

第二部分:系统架构设计

2.1 类图设计

BankSystem
├── Bank
│   ├── accounts: Dict[str, BankAccount]
│   ├── add_account(account: BankAccount)
│   ├── remove_account(account_id: str)
│   ├── get_account(account_id: str) -> BankAccount
│   └── transfer(from_account_id: str, to_account_id: str, amount: float) -> bool
│
├── BankAccount (ABC)
│   ├── account_id: str
│   ├── account_holder: str
│   ├── balance: float
│   ├── deposit(amount: float) -> bool
│   ├── withdraw(amount: float) -> bool
│   ├── get_balance() -> float
│   └── get_account_info() -> str
│
├── SavingsAccount (继承自 BankAccount)
│   ├── min_balance: float
│   ├── interest_rate: float
│   └── calculate_interest() -> float
│
├── CheckingAccount (继承自 BankAccount)
│   ├── overdraft_limit: float
│   ├── transaction_fee: float
│   └── get_available_balance() -> float
│
└── PremiumAccount (继承自 SavingsAccount)
    ├── reward_points: float
    ├── bonus_rate: float
    └── calculate_rewards() -> float

2.2 包结构设计

bank_system/
    __init__.py
    bank.py
    exceptions.py
    accounts/
        __init__.py
        base.py
        savings.py
        checking.py
        premium.py
    transactions/
        __init__.py
        deposit.py
        withdrawal.py
        transfer.py
    utils/
        __init__.py
        validation.py
        logging.py
        security.py
    tests/
        __init__.py
        test_accounts.py
        test_bank.py
        test_transactions.py
    main.py

第三部分:实现异常类

首先,我们定义系统所需的异常类:

# bank_system/exceptions.py

class BankSystemError(Exception):
    """银行系统异常基类"""
    pass

class AccountError(BankSystemError):
    """账户相关异常"""
    pass

class InsufficientFundsError(AccountError):
    """余额不足异常"""
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        super().__init__(f"余额不足。当前余额: ${balance:.2f}, 尝试取款: ${amount:.2f}")

class InvalidAmountError(AccountError):
    """无效金额异常"""
    def __init__(self, amount):
        self.amount = amount
        super().__init__(f"无效金额: ${amount:.2f}。金额必须为正数")

class AccountNotFoundError(AccountError):
    """账户未找到异常"""
    def __init__(self, account_id):
        self.account_id = account_id
        super().__init__(f"账户未找到: {account_id}")

class DailyLimitExceededError(AccountError):
    """每日限额超出异常"""
    def __init__(self, limit, attempted_amount):
        self.limit = limit
        self.attempted_amount = attempted_amount
        super().__init__(f"每日限额超出。限额: ${limit:.2f}, 尝试交易: ${attempted_amount:.2f}")

class TransactionError(BankSystemError):
    """交易相关异常"""
    pass

class SecurityError(BankSystemError):
    """安全相关异常"""
    pass

class AuthenticationError(SecurityError):
    """认证失败异常"""
    def __init__(self, username):
        self.username = username
        super().__init__(f"认证失败: {username}")

第四部分:实现账户基类

接下来,我们实现银行账户的抽象基类:

# bank_system/accounts/base.py

from abc import ABC, abstractmethod
from datetime import datetime
import random
from bank_system.exceptions import InvalidAmountError
from bank_system.utils.validation import validate_name, validate_amount

class BankAccount(ABC):
    """银行账户抽象基类"""
    
    # 类属性
    total_accounts_created = 0
    next_account_id = 1000
    
    def __init__(self, account_holder, initial_balance=0):
        # 输入验证
        validate_name(account_holder)
        validate_amount(initial_balance, allow_zero=True)
        
        # 初始化实例属性
        self._account_holder = account_holder
        self._balance = initial_balance
        self._account_id = self._generate_account_id()
        self._created_date = datetime.now()
        self._transactions = []
        self._is_active = True
        
        # 更新类属性
        BankAccount.total_accounts_created += 1
        
        # 记录创建交易
        if initial_balance > 0:
            self._record_transaction(initial_balance, "初始存款")
    
    def _generate_account_id(self):
        """生成唯一的账户ID"""
        account_id = f"ACC{BankAccount.next_account_id}"
        BankAccount.next_account_id += 1
        return account_id
    
    def _record_transaction(self, amount, description):
        """记录交易"""
        transaction = {
            "date": datetime.now(),
            "amount": amount,
            "description": description,
            "balance_after": self._balance,
            "type": "deposit" if amount >= 0 else "withdrawal"
        }
        self._transactions.append(transaction)
    
    def deposit(self, amount):
        """存款方法"""
        validate_amount(amount)
        
        self._balance += amount
        self._record_transaction(amount, "存款")
        return True
    
    @abstractmethod
    def withdraw(self, amount):
        """取款抽象方法,子类必须实现"""
        pass
    
    def get_balance(self):
        """获取余额"""
        return self._balance
    
    def get_account_info(self):
        """获取账户信息"""
        status = "活跃" if self._is_active else "冻结"
        return (f"账户ID: {self._account_id}, 持有人: {self._account_holder}, "
                f"余额: ${self._balance:.2f}, 状态: {status}")
    
    def get_transaction_history(self):
        """获取交易历史"""
        return self._transactions.copy()
    
    def close_account(self):
        """关闭账户"""
        if self._balance != 0:
            raise ValueError("无法关闭非零余额账户")
        self._is_active = False
        return True
    
    # 魔术方法
    def __str__(self):
        return self.get_account_info()
    
    def __repr__(self):
        return f"{self.__class__.__name__}('{self._account_holder}', {self._balance})"
    
    def __len__(self):
        return len(self._transactions)
    
    def __getitem__(self, index):
        return self._transactions[index]
    
    def __contains__(self, amount):
        return any(t['amount'] == amount for t in self._transactions)
    
    def __eq__(self, other):
        if isinstance(other, BankAccount):
            return self._account_id == other._account_id
        return False
    
    def __hash__(self):
        return hash(self._account_id)
    
    # 上下文管理器支持
    def __enter__(self):
        """进入上下文时调用"""
        print(f"开始处理账户 {self._account_id}")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """退出上下文时调用"""
        print(f"完成处理账户 {self._account_id}")
        if exc_type is not None:
            print(f"处理过程中发生错误: {exc_val}")
        return False  # 不抑制异常

第五部分:实现具体账户类型

现在,我们实现三种具体的账户类型:

5.1 储蓄账户

# bank_system/accounts/savings.py

from .base import BankAccount
from bank_system.exceptions import InsufficientFundsError, DailyLimitExceededError

class SavingsAccount(BankAccount):
    """储蓄账户"""
    
    # 类属性
    default_interest_rate = 0.03
    default_min_balance = 50
    default_daily_limit = 1000
    
    def __init__(self, account_holder, initial_balance=0, 
                 min_balance=None, interest_rate=None, daily_limit=None):
        super().__init__(account_holder, initial_balance)
        
        # 实例属性
        self._min_balance = min_balance or self.default_min_balance
        self._interest_rate = interest_rate or self.default_interest_rate
        self._daily_limit = daily_limit or self.default_daily_limit
        self._daily_withdrawals = 0
        self._last_reset_date = datetime.now().date()
    
    def _reset_daily_counter(self):
        """重置每日计数器"""
        today = datetime.now().date()
        if today != self._last_reset_date:
            self._daily_withdrawals = 0
            self._last_reset_date = today
    
    def withdraw(self, amount):
        """取款实现"""
        from bank_system.utils.validation import validate_amount
        
        validate_amount(amount)
        self._reset_daily_counter()
        
        # 检查余额是否足够
        if self._balance - amount < self._min_balance:
            raise InsufficientFundsError(self._balance, amount)
        
        # 检查每日限额
        if self._daily_withdrawals + amount > self._daily_limit:
            raise DailyLimitExceededError(self._daily_limit, self._daily_withdrawals + amount)
        
        # 执行取款
        self._balance -= amount
        self._daily_withdrawals += amount
        self._record_transaction(-amount, "取款")
        return True
    
    def calculate_interest(self):
        """计算利息"""
        interest = self._balance * self._interest_rate
        return interest
    
    def apply_interest(self):
        """应用利息"""
        interest = self.calculate_interest()
        self.deposit(interest)
        return interest
    
    def get_account_info(self):
        """获取账户信息(重写父类方法)"""
        base_info = super().get_account_info()
        return (f"{base_info}, 类型: 储蓄账户, "
                f"最低余额: ${self._min_balance:.2f}, 利率: {self._interest_rate*100:.1f}%")
    
    # 属性访问器
    @property
    def min_balance(self):
        return self._min_balance
    
    @min_balance.setter
    def min_balance(self, value):
        from bank_system.utils.validation import validate_amount
        validate_amount(value, allow_zero=True)
        self._min_balance = value
    
    @property
    def interest_rate(self):
        return self._interest_rate
    
    @interest_rate.setter
    def interest_rate(self, value):
        if not 0 <= value <= 1:
            raise ValueError("利率必须在0到1之间")
        self._interest_rate = value

5.2 支票账户

# bank_system/accounts/checking.py

from .base import BankAccount
from bank_system.exceptions import InsufficientFundsError

class CheckingAccount(BankAccount):
    """支票账户"""
    
    # 类属性
    default_overdraft_limit = 500
    default_transaction_fee = 1.0
    
    def __init__(self, account_holder, initial_balance=0, 
                 overdraft_limit=None, transaction_fee=None):
        super().__init__(account_holder, initial_balance)
        
        # 实例属性
        self._overdraft_limit = overdraft_limit or self.default_overdraft_limit
        self._transaction_fee = transaction_fee or self.default_transaction_fee
    
    def withdraw(self, amount):
        """取款实现"""
        from bank_system.utils.validation import validate_amount
        
        validate_amount(amount)
        
        # 计算总金额(包括手续费)
        total_amount = amount + self._transaction_fee
        
        # 检查余额是否足够(考虑透支额度)
        available_balance = self._balance + self._overdraft_limit
        if total_amount > available_balance:
            raise InsufficientFundsError(self._balance, amount)
        
        # 执行取款(先扣手续费)
        if self._transaction_fee > 0:
            self._balance -= self._transaction_fee
            self._record_transaction(-self._transaction_fee, "取款手续费")
        
        # 再扣取款金额
        self._balance -= amount
        self._record_transaction(-amount, "取款")
        return True
    
    def get_available_balance(self):
        """获取可用余额(包括透支额度)"""
        return self._balance + self._overdraft_limit
    
    def get_account_info(self):
        """获取账户信息(重写父类方法)"""
        base_info = super().get_account_info()
        return (f"{base_info}, 类型: 支票账户, "
                f"透支额度: ${self._overdraft_limit:.2f}, "
                f"交易手续费: ${self._transaction_fee:.2f}")
    
    # 属性访问器
    @property
    def overdraft_limit(self):
        return self._overdraft_limit
    
    @overdraft_limit.setter
    def overdraft_limit(self, value):
        from bank_system.utils.validation import validate_amount
        validate_amount(value, allow_zero=True)
        self._overdraft_limit = value
    
    @property
    def transaction_fee(self):
        return self._transaction_fee
    
    @transaction_fee.setter
    def transaction_fee(self, value):
        from bank_system.utils.validation import validate_amount
        validate_amount(value, allow_zero=True)
        self._transaction_fee = value

5.3 高级账户

# bank_system/accounts/premium.py

from .savings import SavingsAccount
from bank_system.exceptions import InsufficientFundsError

class PremiumAccount(SavingsAccount):
    """高级账户(继承自储蓄账户)"""
    
    # 类属性
    default_bonus_rate = 0.01
    default_reward_rate = 0.001
    
    def __init__(self, account_holder, initial_balance=0, 
                 min_balance=None, interest_rate=None, daily_limit=None,
                 bonus_rate=None, reward_rate=None):
        # 调用父类构造函数
        super().__init__(account_holder, initial_balance, min_balance, interest_rate, daily_limit)
        
        # 高级账户特有属性
        self._bonus_rate = bonus_rate or self.default_bonus_rate
        self._reward_rate = reward_rate or self.default_reward_rate
        self._reward_points = 0
    
    def deposit(self, amount):
        """存款实现(重写父类方法,添加奖励积分)"""
        from bank_system.utils.validation import validate_amount
        
        validate_amount(amount)
        
        # 调用父类存款方法
        result = super().deposit(amount)
        
        # 计算并添加奖励积分
        if result:
            reward_points = amount * self._reward_rate
            self._reward_points += reward_points
        
        return result
    
    def calculate_interest(self):
        """计算利息(重写父类方法,添加奖金)"""
        base_interest = super().calculate_interest()
        bonus = base_interest * self._bonus_rate
        return base_interest + bonus
    
    def calculate_rewards(self):
        """计算奖励积分价值"""
        return self._reward_points * 0.01  # 每100积分价值1美元
    
    def redeem_rewards(self):
        """兑换奖励积分"""
        if self._reward_points <= 0:
            return 0
        
        reward_value = self.calculate_rewards()
        self.deposit(reward_value)
        
        redeemed_points = self._reward_points
        self._reward_points = 0
        
        return redeemed_points
    
    def get_account_info(self):
        """获取账户信息(重写父类方法)"""
        base_info = super().get_account_info()
        reward_value = self.calculate_rewards()
        return (f"{base_info}, 类型: 高级账户, "
                f"奖励积分: {self._reward_points:.0f}, "
                f"奖励价值: ${reward_value:.2f}, "
                f"奖金利率: {self._bonus_rate*100:.1f}%")
    
    # 属性访问器
    @property
    def reward_points(self):
        return self._reward_points
    
    @property
    def bonus_rate(self):
        return self._bonus_rate
    
    @bonus_rate.setter
    def bonus_rate(self, value):
        if not 0 <= value <= 1:
            raise ValueError("奖金利率必须在0到1之间")
        self._bonus_rate = value
    
    @property
    def reward_rate(self):
        return self._reward_rate
    
    @reward_rate.setter
    def reward_rate(self, value):
        if not 0 <= value <= 1:
            raise ValueError("奖励比率必须在0到1之间")
        self._reward_rate = value

第六部分:实现银行类

现在,我们实现银行类,用于管理所有账户:

# bank_system/bank.py

from .accounts.savings import SavingsAccount
from .accounts.checking import CheckingAccount
from .accounts.premium import PremiumAccount
from .exceptions import AccountNotFoundError, InvalidAmountError
from .utils.security import authenticate

class Bank:
    """银行类,管理所有账户"""
    
    def __init__(self, name):
        self._name = name
        self._accounts = {}  # 账户ID到账户对象的映射
        self._transactions = []  # 所有交易的记录
        self._authenticated = False
    
    def authenticate(self, username, password):
        """认证用户"""
        self._authenticated = authenticate(username, password)
        if not self._authenticated:
            raise AuthenticationError(username)
        return True
    
    def _check_authentication(self):
        """检查认证状态"""
        if not self._authenticated:
            raise SecurityError("需要先进行认证")
    
    def create_account(self, account_type, account_holder, initial_balance=0, **kwargs):
        """创建新账户"""
        self._check_authentication()
        
        # 验证金额
        from .utils.validation import validate_amount
        validate_amount(initial_balance, allow_zero=True)
        
        # 创建账户对象
        account_classes = {
            'savings': SavingsAccount,
            'checking': CheckingAccount,
            'premium': PremiumAccount
        }
        
        if account_type not in account_classes:
            raise ValueError(f"不支持的账户类型: {account_type}")
        
        account_class = account_classes[account_type]
        account = account_class(account_holder, initial_balance, **kwargs)
        
        # 添加到账户列表
        self._accounts[account._account_id] = account
        
        # 记录系统交易
        self._record_system_transaction(f"创建{account_type}账户: {account._account_id}")
        
        return account
    
    def get_account(self, account_id):
        """获取账户"""
        self._check_authentication()
        
        account = self._accounts.get(account_id)
        if account is None:
            raise AccountNotFoundError(account_id)
        return account
    
    def close_account(self, account_id):
        """关闭账户"""
        self._check_authentication()
        
        account = self.get_account(account_id)
        
        # 检查余额
        if account.get_balance() != 0:
            raise ValueError("无法关闭非零余额账户")
        
        # 关闭账户
        account.close_account()
        
        # 从账户列表中移除
        del self._accounts[account_id]
        
        # 记录系统交易
        self._record_system_transaction(f"关闭账户: {account_id}")
        
        return True
    
    def transfer(self, from_account_id, to_account_id, amount):
        """转账"""
        self._check_authentication()
        
        from .utils.validation import validate_amount
        validate_amount(amount)
        
        # 获取账户
        from_account = self.get_account(from_account_id)
        to_account = self.get_account(to_account_id)
        
        # 执行转账
        if from_account.withdraw(amount):
            to_account.deposit(amount)
            
            # 记录系统交易
            self._record_system_transaction(
                f"转账: ${amount:.2f}{from_account_id}{to_account_id}"
            )
            
            return True
        
        return False
    
    def apply_interest_to_all(self):
        """为所有账户应用利息"""
        self._check_authentication()
        
        total_interest = 0
        
        for account in self._accounts.values():
            if hasattr(account, 'apply_interest'):
                interest = account.apply_interest()
                total_interest += interest
        
        # 记录系统交易
        self._record_system_transaction(f"应用利息总计: ${total_interest:.2f}")
        
        return total_interest
    
    def get_total_deposits(self):
        """获取总存款"""
        self._check_authentication()
        
        total = sum(account.get_balance() for account in self._accounts.values())
        return total
    
    def get_accounts_by_type(self, account_type):
        """按类型获取账户"""
        self._check_authentication()
        
        account_classes = {
            'savings': SavingsAccount,
            'checking': CheckingAccount,
            'premium': PremiumAccount
        }
        
        if account_type not in account_classes:
            raise ValueError(f"不支持的账户类型: {account_type}")
        
        target_class = account_classes[account_type]
        return [acc for acc in self._accounts.values() if isinstance(acc, target_class)]
    
    def _record_system_transaction(self, description):
        """记录系统交易"""
        transaction = {
            "date": datetime.now(),
            "description": description,
            "type": "system"
        }
        self._transactions.append(transaction)
    
    def get_system_transactions(self):
        """获取系统交易记录"""
        self._check_authentication()
        return self._transactions.copy()
    
    # 魔术方法
    def __str__(self):
        return f"{self._name}银行 - 账户数: {len(self._accounts)}, 总存款: ${self.get_total_deposits():.2f}"
    
    def __len__(self):
        return len(self._accounts)
    
    def __contains__(self, account_id):
        return account_id in self._accounts
    
    def __iter__(self):
        return iter(self._accounts.values())
    
    # 上下文管理器支持
    def __enter__(self):
        """进入上下文时调用"""
        print(f"开始处理银行: {self._name}")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """退出上下文时调用"""
        print(f"完成处理银行: {self._name}")
        if exc_type is not None:
            print(f"处理过程中发生错误: {exc_val}")
        return False  # 不抑制异常

第七部分:实现工具模块

7.1 验证工具

# bank_system/utils/validation.py

from ..exceptions import InvalidAmountError

def validate_name(name):
    """验证账户名称"""
    if not isinstance(name, str) or not name.strip():
        raise ValueError("账户持有人必须是非空字符串")

def validate_amount(amount, allow_zero=False):
    """验证金额"""
    if not isinstance(amount, (int, float)):
        raise TypeError("金额必须是数字")
    if amount < 0:
        raise InvalidAmountError(amount)
    if amount == 0 and not allow_zero:
        raise InvalidAmountError(amount)

7.2 安全工具

# bank_system/utils/security.py

import hashlib
from ..exceptions import AuthenticationError

# 简单的用户数据库(实际应用中应该使用真正的数据库)
_users = {
    'admin': {
        'password_hash': hashlib.sha256('admin123'.encode()).hexdigest(),
        'role': 'admin'
    },
    'teller': {
        'password_hash': hashlib.sha256('teller123'.encode()).hexdigest(),
        'role': 'teller'
    }
}

def authenticate(username, password):
    """认证用户"""
    if username not in _users:
        return False
    
    password_hash = hashlib.sha256(password.encode()).hexdigest()
    return _users[username]['password_hash'] == password_hash

def get_user_role(username):
    """获取用户角色"""
    if username not in _users:
        return None
    return _users[username]['role']

第八部分:主程序实现

最后,我们实现主程序来演示系统的使用:

# bank_system/main.py

from bank import Bank
from exceptions import BankSystemError, AuthenticationError

def main():
    """主程序"""
    # 创建银行
    bank = Bank("Python银行")
    
    try:
        # 认证
        print("正在进行认证...")
        bank.authenticate("admin", "admin123")
        print("认证成功!")
        
        # 使用上下文管理器
        with bank:
            # 创建账户
            print("\n1. 创建账户:")
            savings = bank.create_account('savings', 'Alice', 1000, min_balance=100)
            checking = bank.create_account('checking', 'Bob', 500, overdraft_limit=200)
            premium = bank.create_account('premium', 'Charlie', 2000, bonus_rate=0.1)
            
            print(f"  创建了储蓄账户: {savings.get_account_info()}")
            print(f"  创建了支票账户: {checking.get_account_info()}")
            print(f"  创建了高级账户: {premium.get_account_info()}")
            
            # 进行交易
            print("\n2. 进行交易:")
            savings.deposit(200)
            checking.withdraw(300)  # 使用透支
            
            print(f"  储蓄账户存款后: {savings.get_account_info()}")
            print(f"  支票账户取款后: {checking.get_account_info()}")
            
            # 转账
            print("\n3. 进行转账:")
            success = bank.transfer(savings._account_id, checking._account_id, 150)
            if success:
                print("  转账成功!")
                print(f"  转账后储蓄账户: {savings.get_account_info()}")
                print(f"  转账后支票账户: {checking.get_account_info()}")
            
            # 计算和应用利息
            print("\n4. 计算利息:")
            savings_interest = savings.calculate_interest()
            premium_interest = premium.calculate_interest()
            
            print(f"  储蓄账户利息: ${savings_interest:.2f}")
            print(f"  高级账户利息: ${premium_interest:.2f}")
            
            # 应用利息
            bank.apply_interest_to_all()
            print(f"  应用利息后储蓄账户: {savings.get_account_info()}")
            print(f"  应用利息后高级账户: {premium.get_account_info()}")
            
            # 高级账户功能
            print("\n5. 高级账户功能:")
            premium.deposit(500)  # 存款获取奖励积分
            print(f"  存款后高级账户: {premium.get_account_info()}")
            
            redeemed = premium.redeem_rewards()
            print(f"  兑换了 {redeemed:.0f} 奖励积分")
            print(f"  兑换后高级账户: {premium.get_account_info()}")
            
            # 银行统计信息
            print("\n6. 银行统计信息:")
            print(f"  银行总存款: ${bank.get_total_deposits():.2f}")
            print(f"  账户总数: {len(bank)}")
            
            savings_accounts = bank.get_accounts_by_type('savings')
            print(f"  储蓄账户数量: {len(savings_accounts)}")
        
        print("\n程序执行完成!")
        
    except AuthenticationError as e:
        print(f"认证失败: {e}")
    except BankSystemError as e:
        print(f"银行系统错误: {e}")
    except Exception as e:
        print(f"发生未知错误: {e}")

if __name__ == "__main__":
    main()

第九部分:测试程序

我们还需要编写测试程序来验证系统的正确性:

# bank_system/tests/test_accounts.py

import unittest
from bank_system.accounts.savings import SavingsAccount
from bank_system.accounts.checking import CheckingAccount
from bank_system.accounts.premium import PremiumAccount
from bank_system.exceptions import InsufficientFundsError, InvalidAmountError

class TestAccounts(unittest.TestCase):
    """测试账户类"""
    
    def test_savings_account_creation(self):
        """测试储蓄账户创建"""
        account = SavingsAccount("Test User", 1000)
        self.assertEqual(account.get_balance(), 1000)
        self.assertEqual(account.min_balance, 50)
    
    def test_savings_account_withdraw_insufficient_funds(self):
        """测试储蓄账户余额不足取款"""
        account = SavingsAccount("Test User", 100, min_balance=50)
        with self.assertRaises(InsufficientFundsError):
            account.withdraw(60)  # 余额100-60=40 < 最低余额50
    
    def test_checking_account_overdraft(self):
        """测试支票账户透支"""
        account = CheckingAccount("Test User", 100, overdraft_limit=50)
        # 可以取款100+50=150,但需要支付手续费1.0
        # 所以实际可以取款149
        self.assertTrue(account.withdraw(149))
        self.assertAlmostEqual(account.get_balance(), -50)  # 100 - 149 - 1 = -50
    
    def test_premium_account_rewards(self):
        """测试高级账户奖励积分"""
        account = PremiumAccount("Test User", 1000, reward_rate=0.01)
        account.deposit(500)  # 应该获得5积分
        self.assertAlmostEqual(account.reward_points, 5)
    
    def test_invalid_amount(self):
        """测试无效金额"""
        account = SavingsAccount("Test User", 1000)
        with self.assertRaises(InvalidAmountError):
            account.deposit(-100)

if __name__ == '__main__':
    unittest.main()

第十部分:项目总结与扩展

10.1 项目总结

在这个实战项目中,我们实现了一个完整的面向对象银行账户管理系统,具有以下特点:

  1. 完整的面向对象设计:使用继承、多态、封装等OOP概念
  2. 多种账户类型:支持储蓄账户、支票账户和高级账户
  3. 健壮的异常处理:自定义异常类处理各种错误情况
  4. 丰富的功能:存款、取款、转账、利息计算、奖励积分等
  5. 安全机制:用户认证和权限控制
  6. 完整的测试:单元测试验证系统正确性

10.2 扩展方向

这个系统还可以进一步扩展:

  1. 数据库集成:使用SQLite或MySQL存储账户数据
  2. Web界面:使用Flask或Django创建Web界面
  3. API接口:创建RESTful API供其他系统调用
  4. 更多账户类型:添加商业账户、学生账户等
  5. 高级功能:支持贷款、投资、外汇交易等
  6. 数据分析:添加交易分析和报表功能
  7. 多币种支持:支持不同货币的账户和交易

10.3 学习收获

通过这个项目,我们实践了以下Python编程概念:

  • 类和对象的创建与使用
  • 继承和多态的应用
  • 抽象基类和接口的设计
  • 魔术方法的实现
  • 异常处理的最佳实践
  • 模块和包的组织
  • 单元测试的编写

这个完整的银行账户管理系统展示了Python面向对象编程的强大能力,涵盖了从基础到高级的多个概念。通过这个实战项目,你应该对Python面向对象编程有了更深入的理解,并能够将这些知识应用到实际项目中。

更多推荐