面向对象编程(OOP)让你用现实世界的思维来组织代码,把数据和操作封装成对象,让代码更模块化、更易维护
从面条代码到清晰架构
面向过程 vs 面向对象
python
# 🚫 面向过程:一堆散乱的函数和数据
def calculate_employee_salary(hours_worked, hourly_rate, tax_rate):
gross_pay = hours_worked * hourly_rate
tax_amount = gross_pay * tax_rate
net_pay = gross_pay - tax_amount
return net_pay
def print_employee_info(name, department, salary):
print(f"{name} 在 {department} 部门,月薪 {salary}")
def save_employee_to_db(name, department, salary):
# 模拟保存到数据库
print(f"保存 {name} 的信息到数据库")
# 使用这些函数
name = "张三"
department = "技术部"
hours_worked = 160
hourly_rate = 100
tax_rate = 0.2
salary = calculate_employee_salary(hours_worked, hourly_rate, tax_rate)
print_employee_info(name, department, salary)
save_employee_to_db(name, department, salary)
现在看看面向对象的做法:
python
# ✅ 面向对象:清晰的封装
class Employee:
def __init__(self, name, department, hourly_rate):
self.name = name
self.department = department
self.hourly_rate = hourly_rate
self.tax_rate = 0.2
def calculate_salary(self, hours_worked):
gross_pay = hours_worked * self.hourly_rate
tax_amount = gross_pay * self.tax_rate
return gross_pay - tax_amount
def display_info(self, hours_worked):
salary = self.calculate_salary(hours_worked)
print(f"{self.name} 在 {self.department} 部门,月薪 {salary}")
def save_to_database(self):
print(f"保存 {self.name} 的信息到数据库")
# 使用对象
employee = Employee("张三", "技术部", 100)
employee.display_info(160)
employee.save_to_database()
面向对象三大支柱
1. 封装:信息隐藏的艺术
python
class BankAccount:
def __init__(self, account_holder, initial_balance=0):
self.account_holder = account_holder
self._balance = initial_balance # 受保护的属性
self.__account_number = self._generate_account_number() # 私有属性
def _generate_account_number(self):
"""生成账户号码(内部方法)"""
import random
return f"ACC{random.randint(100000, 999999)}"
def deposit(self, amount):
"""存款"""
if amount > 0:
self._balance += amount
print(f"成功存款 {amount},当前余额: {self._balance}")
else:
print("存款金额必须大于0")
def withdraw(self, amount):
"""取款"""
if 0 < amount <= self._balance:
self._balance -= amount
print(f"成功取款 {amount},当前余额: {self._balance}")
return True
else:
print("取款失败:余额不足或金额无效")
return False
def get_balance(self):
"""获取余额(通过方法访问受保护属性)"""
return self._balance
def get_account_info(self):
"""获取账户信息(公开接口)"""
return {
"account_holder": self.account_holder,
"balance": self._balance,
"account_number": self.__account_number # 只能在类内部访问
}
# 使用封装
account = BankAccount("李四", 1000)
account.deposit(500) # ✅ 正确的操作方式
# account._balance = 1000000 # ❌ 不应该直接修改内部状态
# print(account.__account_number) # ❌ 无法访问私有属性
print(f"当前余额: {account.get_balance()}")
print(f"账户信息: {account.get_account_info()}")
2. 继承:代码复用的智慧
python
# 基类:通用员工
class Employee:
def __init__(self, name, employee_id, base_salary):
self.name = name
self.employee_id = employee_id
self.base_salary = base_salary
def calculate_salary(self):
"""计算基本工资"""
return self.base_salary
def get_info(self):
"""获取员工信息"""
return f"{self.name} (ID: {self.employee_id})"
# 派生类:经理
class Manager(Employee):
def __init__(self, name, employee_id, base_salary, bonus):
super().__init__(name, employee_id, base_salary) # 调用父类构造器
self.bonus = bonus
self.team_size = 0
def calculate_salary(self):
"""重写工资计算方法(经理有奖金)"""
return self.base_salary + self.bonus
def manage_team(self, team_size):
"""经理特有的方法"""
self.team_size = team_size
print(f"{self.name} 正在管理 {team_size} 人的团队")
# 派生类:开发人员
class Developer(Employee):
def __init__(self, name, employee_id, base_salary, programming_language):
super().__init__(name, employee_id, base_salary)
self.programming_language = programming_language
self.projects = []
def add_project(self, project_name):
"""开发人员特有的方法"""
self.projects.append(project_name)
print(f"{self.name} 参与了项目: {project_name}")
def get_info(self):
"""重写获取信息方法"""
base_info = super().get_info()
return f"{base_info} - {self.programming_language} 开发工程师"
# 使用继承
manager = Manager("王总监", "M001", 15000, 5000)
developer = Developer("张工程师", "D001", 12000, "Python")
print("=== 员工信息 ===")
print(f"经理: {manager.get_info()}, 月薪: {manager.calculate_salary()}")
print(f"开发: {developer.get_info()}, 月薪: {developer.calculate_salary()}")
manager.manage_team(8) # 经理特有方法
developer.add_project("电商系统") # 开发人员特有方法
3. 多态:灵活应对变化
python
from math import pi
class Shape:
"""形状基类"""
def area(self):
"""计算面积(抽象方法)"""
raise NotImplementedError("子类必须实现此方法")
def perimeter(self):
"""计算周长(抽象方法)"""
raise NotImplementedError("子类必须实现此方法")
class Rectangle(Shape):
"""矩形"""
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
class Circle(Shape):
"""圆形"""
def __init__(self, radius):
self.radius = radius
def area(self):
return pi * self.radius ** 2
def perimeter(self):
return 2 * pi * self.radius
class Triangle(Shape):
"""三角形"""
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def area(self):
# 使用海伦公式
s = self.perimeter() / 2
return (s * (s - self.a) * (s - self.b) * (s - self.c)) ** 0.5
def perimeter(self):
return self.a + self.b + self.c
# 多态的威力:统一处理不同对象
def print_shape_info(shape):
"""打印形状信息 - 接受任何Shape对象"""
print(f"{type(shape).__name__}: 面积={shape.area():.2f}, 周长={shape.perimeter():.2f}")
# 创建不同形状
shapes = [
Rectangle(10, 5),
Circle(3),
Triangle(3, 4, 5)
]
print("=== 多态演示 ===")
for shape in shapes:
print_shape_info(shape) # 同样的接口,不同的行为
高级面向对象特性
属性装饰器:智能属性访问
python
class SmartProduct:
def __init__(self, name, price):
self.name = name
self._price = price
self._discount = 0
@property
def price(self):
"""获取价格(带折扣)"""
return self._price * (1 - self._discount)
@price.setter
def price(self, value):
"""设置价格(带验证)"""
if value < 0:
raise ValueError("价格不能为负数")
self._price = value
@property
def discount(self):
"""获取折扣"""
return self._discount
@discount.setter
def discount(self, value):
"""设置折扣(带验证)"""
if not 0 <= value <= 1:
raise ValueError("折扣必须在0到1之间")
self._discount = value
@property
def discounted_price(self):
"""计算折后价格(只读属性)"""
return self._price * (1 - self._discount)
# 使用属性装饰器
product = SmartProduct("笔记本电脑", 6000)
print(f"原价: {product.price}")
product.discount = 0.1 # 设置9折
print(f"9折价格: {product.price}")
print(f"折后价格: {product.discounted_price}")
# product.price = -100 # 会抛出 ValueError
类方法和静态方法
python
class DateUtils:
"""日期工具类"""
# 类属性
DATE_FORMAT = "YYYY-MM-DD"
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def from_string(cls, date_string):
"""类方法:从字符串创建对象"""
year, month, day = map(int, date_string.split('-'))
return cls(year, month, day)
@classmethod
def get_date_format(cls):
"""类方法:获取日期格式"""
return cls.DATE_FORMAT
@staticmethod
def is_leap_year(year):
"""静态方法:判断是否是闰年(与类相关但不依赖实例)"""
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
def display(self):
"""实例方法"""
return f"{self.year}-{self.month:02d}-{self.day:02d}"
# 使用不同方法
print("=== 方法类型演示 ===")
# 类方法使用
date1 = DateUtils.from_string("2024-01-15")
print(f"从字符串创建: {date1.display()}")
print(f"日期格式: {DateUtils.get_date_format()}")
# 静态方法使用
print(f"2024是闰年: {DateUtils.is_leap_year(2024)}")
print(f"2023是闰年: {DateUtils.is_leap_year(2023)}")
# 实例方法使用
date2 = DateUtils(2024, 12, 25)
print(f"直接创建: {date2.display()}")
实战:简易学生管理系统
python
class Student:
"""学生类"""
def __init__(self, student_id, name, age):
self.student_id = student_id
self.name = name
self.age = age
self.courses = []
def enroll_course(self, course_name):
"""选课"""
if course_name not in self.courses:
self.courses.append(course_name)
print(f"{self.name} 成功选修了 {course_name}")
else:
print(f"{self.name} 已经选修过 {course_name} 了")
def drop_course(self, course_name):
"""退课"""
if course_name in self.courses:
self.courses.remove(course_name)
print(f"{self.name} 成功退选了 {course_name}")
else:
print(f"{self.name} 没有选修 {course_name}")
def display_info(self):
"""显示学生信息"""
print(f"\n学生信息:")
print(f" 学号: {self.student_id}")
print(f" 姓名: {self.name}")
print(f" 年龄: {self.age}")
print(f" 选修课程: {', '.join(self.courses) if self.courses else '无'}")
class StudentManager:
"""学生管理器"""
def __init__(self):
self.students = {}
def add_student(self, student_id, name, age):
"""添加学生"""
if student_id in self.students:
print(f"学号 {student_id} 已存在")
return False
self.students[student_id] = Student(student_id, name, age)
print(f"成功添加学生: {name}")
return True
def remove_student(self, student_id):
"""删除学生"""
if student_id in self.students:
student_name = self.students[student_id].name
del self.students[student_id]
print(f"成功删除学生: {student_name}")
return True
else:
print(f"学号 {student_id} 不存在")
return False
def find_student(self, student_id):
"""查找学生"""
return self.students.get(student_id)
def list_all_students(self):
"""列出所有学生"""
if not self.students:
print("还没有学生信息")
return
print("\n=== 所有学生信息 ===")
for student in self.students.values():
student.display_info()
# 使用学生管理系统
def demo_student_management():
"""演示学生管理系统"""
manager = StudentManager()
# 添加学生
manager.add_student("S001", "张三", 20)
manager.add_student("S002", "李四", 19)
manager.add_student("S003", "王五", 21)
# 学生选课
zhang_san = manager.find_student("S001")
if zhang_san:
zhang_san.enroll_course("Python编程")
zhang_san.enroll_course("数据结构")
zhang_san.enroll_course("Python编程") # 重复选课
li_si = manager.find_student("S002")
if li_si:
li_si.enroll_course("Java编程")
li_si.enroll_course("算法设计")
# 显示所有学生
manager.list_all_students()
# 学生退课
if zhang_san:
zhang_san.drop_course("数据结构")
zhang_san.drop_course("不存在的课程") # 退选未选修的课程
# 再次显示信息
print("\n=== 退课后的信息 ===")
manager.list_all_students()
# 删除学生
manager.remove_student("S003")
manager.remove_student("S999") # 删除不存在的学生
# 最终学生列表
print("\n=== 最终学生列表 ===")
manager.list_all_students()
# 运行演示
demo_student_management()
面向对象设计原则
1. 单一职责原则
python
# ✅ 好的设计:每个类只有一个职责
class User:
def __init__(self, name, email):
self.name = name
self.email = email
class UserValidator:
@staticmethod
def validate_email(email):
return "@" in email
class UserRepository:
def save(self, user):
print(f"保存用户 {user.name} 到数据库")
2. 开放封闭原则
python
class Notification:
def send(self, message):
pass
class EmailNotification(Notification):
def send(self, message):
print(f"发送邮件: {message}")
class SMSNotification(Notification):
def send(self, message):
print(f"发送短信: {message}")
# 可以轻松添加新的通知方式,不需要修改现有代码
class WeChatNotification(Notification):
def send(self, message):
print(f"发送微信: {message}")
总结:从代码工人到架构师
面向对象编程的核心价值:让代码从"能工作"升级到"易维护、易扩展、易理解"。 记住这三个关键转变:
- 思维转变:从"怎么做"到"是什么" - 思考对象而不是步骤
- 封装思维:把相关的数据和行为组织在一起,隐藏内部细节
- 复用思维:通过继承和多态,避免重复造轮子