本文目录导读:

我来为你详细讲解面向对象封装的完整案例,从基础到进阶。
基础封装案例:银行账户
简单属性封装
class BankAccount:
"""银行账户类 - 基础封装"""
def __init__(self, account_number, owner, balance=0):
self._account_number = account_number # 受保护属性
self._owner = owner # 受保护属性
self._balance = balance # 私有属性(用_表示)
self._transactions = [] # 交易记录
# 获取余额(只读属性)
def get_balance(self):
"""获取当前余额"""
return self._balance
# 存款
def deposit(self, amount):
"""存款操作"""
if amount <= 0:
raise ValueError("存款金额必须大于0")
self._balance += amount
self._transactions.append(f"存款: +{amount}元")
return self._balance
# 取款
def withdraw(self, amount):
"""取款操作"""
if amount <= 0:
raise ValueError("取款金额必须大于0")
if amount > self._balance:
raise ValueError("余额不足")
self._balance -= amount
self._transactions.append(f"取款: -{amount}元")
return self._balance
# 查看交易记录
def get_transactions(self):
"""获取交易记录副本,防止外部修改"""
return self._transactions.copy()
# 账户信息
def __str__(self):
return f"账户: {self._account_number}, 户主: {self._owner}, 余额: {self._balance}元"
使用@property装饰器
class BankAccountV2:
"""使用@property装饰器的银行账户"""
def __init__(self, account_number, owner, balance=0):
self._account_number = account_number
self._owner = owner
self._balance = balance
self._transactions = []
# 只读属性
@property
def account_number(self):
"""账户号只读"""
return self._account_number
@property
def owner(self):
"""户主只读"""
return self._owner
@property
def balance(self):
"""余额只读"""
return self._balance
@property
def transactions(self):
"""交易记录返回副本"""
return self._transactions.copy()
# 存款(修改方法)
def deposit(self, amount):
"""存款"""
self._validate_amount(amount)
self._balance += amount
self._transactions.append(("deposit", amount))
def withdraw(self, amount):
"""取款"""
self._validate_amount(amount)
if amount > self._balance:
raise ValueError("余额不足")
self._balance -= amount
self._transactions.append(("withdraw", amount))
# 私有辅助方法
def _validate_amount(self, amount):
"""验证金额合法性"""
if not isinstance(amount, (int, float)):
raise TypeError("金额必须是数字")
if amount <= 0:
raise ValueError("金额必须大于0")
def __str__(self):
return f"账户: {self.account_number}, 户主: {self.owner}, 余额: {self.balance}元"
中级封装案例:员工管理系统
from datetime import datetime
import re
class Employee:
"""员工类 - 中级封装"""
def __init__(self, emp_id, name, department, salary):
self._id = emp_id # 员工ID
self._name = name # 姓名
self._department = department # 部门
self._salary = salary # 工资
self._email = None # 邮箱
self._hire_date = datetime.now() # 入职日期
self._performance_scores = [] # 绩效评分
# 姓名(可读,不可直接修改)
@property
def name(self):
return self._name
# 部门(可读可修改)
@property
def department(self):
return self._department
@department.setter
def department(self, value):
"""设置部门,带验证"""
if not value or not value.strip():
raise ValueError("部门不能为空")
self._department = value.strip()
# 工资(提供get和set)
@property
def salary(self):
return self._salary
@salary.setter
def salary(self, value):
"""设置工资,带验证"""
if not isinstance(value, (int, float)):
raise TypeError("工资必须是数字")
if value < 0:
raise ValueError("工资不能为负")
self._salary = value
# 邮箱(带格式验证)
@property
def email(self):
return self._email
@email.setter
def email(self, value):
"""设置邮箱,验证格式"""
if value and not re.match(r'^[\w\.-]+@[\w\.-]+\.\w+$', value):
raise ValueError("邮箱格式不正确")
self._email = value
# 添加绩效评分
def add_performance_score(self, score):
"""添加绩效评分"""
if not isinstance(score, (int, float)):
raise TypeError("评分必须是数字")
if not 0 <= score <= 100:
raise ValueError("评分范围0-100")
self._performance_scores.append(score)
# 获取平均绩效
def get_average_performance(self):
"""获取平均绩效评分"""
if not self._performance_scores:
return 0
return sum(self._performance_scores) / len(self._performance_scores)
# 获取员工信息
def get_employee_info(self):
"""获取员工完整信息"""
return {
"ID": self._id,
"姓名": self._name,
"部门": self._department,
"工资": self._salary,
"邮箱": self._email or "未设置",
"入职日期": self._hire_date.strftime("%Y-%m-%d"),
"平均绩效": self.get_average_performance()
}
# 使用示例
emp = Employee("EMP001", "张三", "技术部", 15000)
emp.email = "zhangsan@company.com"
emp.add_performance_score(85)
emp.add_performance_score(92)
emp.add_performance_score(78)
print(emp.get_employee_info())
高级封装案例:订单管理系统
from typing import List, Dict, Optional
from datetime import datetime
import json
class OrderItem:
"""订单项类"""
def __init__(self, product_id: str, product_name: str, price: float, quantity: int):
self._product_id = product_id
self._product_name = product_name
self._price = price
self._quantity = quantity
@property
def product_id(self):
return self._product_id
@property
def subtotal(self) -> float:
"""计算小计"""
return self._price * self._quantity
def to_dict(self) -> Dict:
"""转为字典"""
return {
"product_id": self._product_id,
"product_name": self._product_name,
"price": self._price,
"quantity": self._quantity,
"subtotal": self.subtotal
}
def __str__(self):
return f"{self._product_name} x{self._quantity} = ¥{self.subtotal}"
class Order:
"""订单类 - 高级封装"""
def __init__(self, order_id: str, customer_name: str):
self._order_id = order_id
self._customer_name = customer_name
self._items: List[OrderItem] = []
self._status = "pending" # pending, paid, shipped, completed, cancelled
self._created_at = datetime.now()
self._discount_rate = 0.0 # 折扣率,0-1之间
# 订单状态常量
STATUS_PENDING = "pending"
STATUS_PAID = "paid"
STATUS_SHIPPED = "shipped"
STATUS_COMPLETED = "completed"
STATUS_CANCELLED = "cancelled"
@property
def order_id(self):
return self._order_id
@property
def status(self):
return self._status
@property
def created_at(self):
return self._created_at
@property
def total_amount(self) -> float:
"""计算订单总额"""
total = sum(item.subtotal for item in self._items)
return total * (1 - self._discount_rate)
def add_item(self, item: OrderItem):
"""添加订单项"""
if self._status != self.STATUS_PENDING:
raise ValueError("只有待处理状态的订单可以添加商品")
self._items.append(item)
def remove_item(self, product_id: str):
"""移除订单项"""
if self._status != self.STATUS_PENDING:
raise ValueError("只有待处理状态的订单可以移除商品")
self._items = [item for item in self._items if item.product_id != product_id]
def set_discount(self, rate: float):
"""设置折扣"""
if not 0 <= rate <= 0.9:
raise ValueError("折扣率必须在0-0.9之间")
self._discount_rate = rate
def update_status(self, new_status: str):
"""更新订单状态"""
valid_transitions = {
self.STATUS_PENDING: [self.STATUS_PAID, self.STATUS_CANCELLED],
self.STATUS_PAID: [self.STATUS_SHIPPED, self.STATUS_CANCELLED],
self.STATUS_SHIPPED: [self.STATUS_COMPLETED],
self.STATUS_COMPLETED: [],
self.STATUS_CANCELLED: []
}
if new_status not in valid_transitions.get(self._status, []):
raise ValueError(f"不能从{self._status}状态转换为{new_status}状态")
self._status = new_status
def to_dict(self) -> Dict:
"""转为字典"""
return {
"order_id": self._order_id,
"customer_name": self._customer_name,
"status": self._status,
"created_at": self._created_at.isoformat(),
"items": [item.to_dict() for item in self._items],
"discount_rate": self._discount_rate,
"total_amount": self.total_amount
}
def save_to_file(self, filepath: str):
"""保存订单到文件"""
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(self.to_dict(), f, ensure_ascii=False, indent=2)
def __str__(self):
items_str = "\n".join(str(item) for item in self._items)
return f"订单号: {self._order_id}\n客户: {self._customer_name}\n状态: {self._status}\n{items_str}\n总额: ¥{self.total_amount}"
# 使用示例
order = Order("ORD-2024-001", "李四")
# 添加订单项
order.add_item(OrderItem("P001", "笔记本电脑", 5999.00, 1))
order.add_item(OrderItem("P002", "无线鼠标", 199.00, 2))
order.add_item(OrderItem("P003", "键盘", 299.00, 1))
# 设置折扣
order.set_discount(0.1) # 10%折扣
print(f"订单总额: ¥{order.total_amount}")
order.save_to_file("order.json")
# 尝试不合法状态转换
try:
order.update_status(order.STATUS_COMPLETED) # 从pending直接到completed不合法
except ValueError as e:
print(f"状态转换错误: {e}")
封装的实践原则
访问控制级别
class EncapsulationExample:
"""封装级别示例"""
def __init__(self):
self.public_attr = "公开属性" # 公共属性
self._protected_attr = "受保护属性" # 受保护(约定)
self.__private_attr = "私有属性" # 私有(name mangling)
def public_method(self):
"""公共方法"""
return "公开方法"
def _protected_method(self):
"""受保护方法"""
return "受保护方法"
def __private_method(self):
"""私有方法"""
return "私有方法"
def access_private(self):
"""在类内部访问私有成员"""
return self.__private_attr + " - " + self.__private_method()
封装的最佳实践
class BestPractices:
"""封装最佳实践示例"""
def __init__(self):
# 1. 使用下划线约定
self._data = []
# 2. 使用@property提供只读属性
self._read_only = "不可修改"
# 3. 在setter中添加验证
self._age = 0
# 2. 只读属性
@property
def read_only(self):
return self._read_only
# 3. 带验证的setter
@property
def age(self):
return self._age
@age.setter
def age(self, value):
"""验证年龄"""
if not isinstance(value, int):
raise TypeError("年龄必须是整数")
if not 0 <= value <= 150:
raise ValueError("年龄范围无效")
self._age = value
# 4. 返回副本而不是直接返回内部数据
def get_data(self):
"""返回数据副本"""
return self._data.copy()
# 5. 提供明确的操作方法
def add_item(self, item):
"""添加数据"""
self._data.append(item)
def remove_item(self, item):
"""移除数据"""
if item in self._data:
self._data.remove(item)
else:
raise ValueError(f"数据不存在: {item}")
总结要点
封装的好处:
- 数据安全:防止外部直接访问和修改内部数据
- 简化接口:只暴露必要的操作接口
- 灵活性:修改内部实现不影响外部调用
- 可维护性:代码结构清晰,易于维护
封装的原则:
- 最小化暴露:只暴露必要的方法和属性
- 数据验证:在setter中进行数据验证
- 返回副本:对于可变对象,返回副本而非原对象
- 提供明确方法:通过方法操作数据,而非直接访问
就是封装的完整案例,从简单到复杂,覆盖了封装的各个层面,选择哪种封装方式,需要根据项目的具体需求来确定。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播