引言:面向对象编程的核心概念

面向对象编程(Object-Oriented Programming,简称OOP)是现代软件开发中最重要和最流行的编程范式之一。Python作为一门支持多范式的编程语言,对OOP提供了出色的支持。在本篇文章中,我们将深入探讨Python中面向对象编程的各个方面,从基础概念到高级应用,帮助您全面掌握这一强大的编程范式。

面向对象编程的核心思想是将现实世界中的实体抽象为程序中的”对象”。每个对象都包含数据(属性)和操作数据的方法(行为)。这种编程方式更符合人类的自然思维方式,使代码更加模块化、可重用和易于维护。

让我们通过一个简单的例子来理解OOP的基本概念:

# 定义一个简单的类:汽车
class Car:
    # 初始化方法(构造函数)
    def __init__(self, brand, model, color):
        self.brand = brand    # 品牌属性
        self.model = model    # 型号属性
        self.color = color    # 颜色属性
        self.speed = 0        # 速度属性,默认为0
    
    # 方法:加速
    def accelerate(self, amount):
        self.speed += amount
        print(f"{self.brand} {self.model} 加速到 {self.speed} km/h")
    
    # 方法:刹车
    def brake(self, amount):
        if self.speed >= amount:
            self.speed -= amount
            print(f"{self.brand} {self.model} 减速到 {self.speed} km/h")
        else:
            self.speed = 0
            print(f"{self.brand} {self.model} 已完全停止")
    
    # 方法:显示车辆信息
    def display_info(self):
        return f"车辆信息: {self.color} {self.brand} {self.model}, 当前速度: {self.speed} km/h"

# 创建汽车对象
my_car = Car("Toyota", "Camry", "黑色")
print(my_car.display_info())
my_car.accelerate(60)
my_car.brake(20)
print(my_car.display_info())

这个例子展示了OOP的几个关键元素:

  1. 类(Class):Car是定义汽车的蓝图
  2. 属性(Attributes):brand, model, color, speed存储对象的状态
  3. 方法(Methods):accelerate, brake, display_info定义对象的行为
  4. 对象(Object):my_car是Car类的具体实例

类与对象:Python OOP的基础

类的定义与实例化

在Python中,类使用class关键字定义。类名通常采用驼峰命名法(CamelCase),而方法和属性使用蛇形命名法(snake_case)。

class Dog:
    # 类属性(所有实例共享)
    species = "Canis familiaris"
    
    # 实例初始化方法
    def __init__(self, name, age, breed):
        # 实例属性(每个实例独立)
        self.name = name
        self.age = age
        self.breed = breed
    
    # 实例方法
    def bark(self):
        return f"{self.name} 正在汪汪叫!"
    
    def human_age(self):
        return f"{self.name} 的人类年龄是 {self.age * 7} 岁"

# 创建Dog类的实例
dog1 = Dog("Buddy", 3, "Golden Retriever")
dog2 = Dog("Max", 5, "German Shepherd")

# 访问属性和方法
print(dog1.name)        # 输出: Buddy
print(dog2.bark())      # 输出: Max 正在汪汪叫!
print(Dog.species)      # 输出: Canis familiaris
print(dog1.human_age()) # 输出: Buddy 的人类年龄是 21 岁

self参数详解

在Python类的方法中,第一个参数通常是self,它代表类的当前实例。通过self,我们可以访问实例的属性和方法。虽然在调用方法时不需要显式传递self(Python会自动处理),但在方法定义中必须包含它。

class Rectangle:
    def __init__(self, width, height):
        # 这里的self代表新创建的实例
        self.width = width
        self.height = height
    
    def area(self):
        # 通过self访问实例属性
        return self.width * self.height
    
    def perimeter(self):
        return 2 * (self.width + self.height)
    
    def is_square(self):
        # 在类的方法中调用另一个方法也需要self
        return self.width == self.height

# 创建实例
rect = Rectangle(5, 10)
print(f"面积: {rect.area()}")        # 输出: 面积: 50
print(f"周长: {rect.perimeter()}")   # 输出: 周长: 30
print(f"是正方形吗? {rect.is_square()}") # 输出: 是正方形吗? False

类属性与实例属性

Python中有两种类型的属性:

  • 类属性:属于类本身,所有实例共享
  • 实例属性:属于特定实例,每个实例独立
class Employee:
    # 类属性
    company = "TechCorp"
    employee_count = 0
    
    def __init__(self, name, position):
        # 实例属性
        self.name = name
        self.position = position
        Employee.employee_count += 1  # 每次创建实例时增加计数
    
    @classmethod
    def get_employee_count(cls):
        return f"公司共有 {cls.employee_count} 名员工"

# 创建员工实例
emp1 = Employee("Alice", "Developer")
emp2 = Employee("Bob", "Designer")

# 访问类属性
print(Employee.company)           # 输出: TechCorp
print(Employee.get_employee_count()) # 输出: 公司共有 2 名员工

# 实例也可以访问类属性
print(emp1.company)               # 输出: TechCorp

# 修改类属性会影响所有实例
Employee.company = "NewTechCorp"
print(emp2.company)               # 输出: NewTechCorp

继承与多态:扩展和重用代码

单继承与方法重写

继承允许一个类(子类)基于另一个类(父类)来创建。子类会继承父类的所有属性和方法,并可以添加新的属性和方法,或重写已有的方法。

# 父类:动物
class Animal:
    def __init__(self, name, species):
        self.name = name
        self.species = species
    
    def speak(self):
        return f"{self.name} 发出声音"
    
    def __str__(self):
        return f"{self.name} ({self.species})"

# 子类:猫,继承自Animal
class Cat(Animal):
    def __init__(self, name, color, lives=9):
        # 调用父类的初始化方法
        super().__init__(name, "Felis catus")
        self.color = color
        self.lives = lives
    
    # 重写父类的speak方法
    def speak(self):
        return f"{self.name} 说: 喵喵喵!"
    
    # 子类特有方法
    def lose_life(self):
        if self.lives > 0:
            self.lives -= 1
            return f"{self.name} 失去了一条生命,还剩 {self.lives} 条"
        else:
            return f"{self.name} 已经没有生命了"

# 创建实例
generic_animal = Animal("某动物", "未知物种")
my_cat = Cat("Whiskers", "橘色", 9)

# 测试继承和方法重写
print(generic_animal.speak())  # 输出: 某动物 发出声音
print(my_cat.speak())          # 输出: Whiskers 说: 喵喵喵!
print(my_cat)                  # 输出: Whiskers (Felis catus)
print(my_cat.lose_life())      # 输出: Whiskers 失去了一条生命,还剩 8 条

多继承与MRO(方法解析顺序)

Python支持多继承,即一个类可以同时继承多个父类。当多个父类有同名方法时,Python使用C3线性化算法确定方法解析顺序(MRO)。

class Flyer:
    def __init__(self, name):
        self.name = name
    
    def move(self):
        return f"{self.name} 在飞行"

class Swimmer:
    def __init__(self, name):
        self.name = name
    
    def move(self):
        return f"{self.name} 在游泳"

# 多继承:鸭子既会飞又会游
class Duck(Flyer, Swimmer):
    def __init__(self, name):
        # 注意:这里只调用第一个父类的__init__
        Flyer.__init__(self, name)
    
    def move(self):
        # 可以选择调用特定父类的方法
        return f"{self.name} 说: 我可以同时飞行和游泳!\n" \
               f"  飞行: {Flyer.move(self)}\n" \
               f"  游泳: {Swimmer.move(self)}"

# 查看MRO
print(Duck.mro())
# 输出: [<class '__main__.Duck'>, <class '__main__.Flyer'>, <class '__main__.Swimmer'>, <class 'object'>]

donald = Duck("Donald")
print(donald.move())
# 输出:
# Donald 说: 我可以同时飞行和游泳!
#   飞行: Donald 在飞行
#   游泳: Donald 在游泳

多态性

多态是指不同类的对象对同一消息做出不同的响应。在Python中,多态通过方法重写实现,不需要显式的接口定义。

class Shape:
    def area(self):
        pass
    
    def perimeter(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14159 * self.radius ** 2
    
    def perimeter(self):
        return 2 * 3.14159 * self.radius

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 Triangle(Shape):
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
    
    def area(self):
        # 使用海伦公式
        s = (self.a + self.b + self.c) / 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):
    print(f"形状: {shape.__class__.__name__}")
    print(f"面积: {shape.area():.2f}")
    print(f"周长: {shape.perimeter():.2f}")
    print("-" * 30)

# 创建不同形状对象
shapes = [
    Circle(5),
    Rectangle(4, 6),
    Triangle(3, 4, 5)
]

# 统一处理
for shape in shapes:
    print_shape_info(shape)

封装与访问控制

公有与私有成员

Python通过命名约定实现访问控制,而不是严格的访问修饰符。单下划线_表示保护成员,双下划线__表示私有成员(名称修饰)。

class BankAccount:
    def __init__(self, account_holder, initial_balance=0):
        self.account_holder = account_holder  # 公有属性
        self._balance = initial_balance       # 保护属性(约定)
        self.__pin = "1234"                   # 私有属性(名称修饰)
    
    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
            return f"存入 {amount},当前余额: {self._balance}"
        else:
            return "存款金额必须大于0"
    
    def withdraw(self, amount, pin):
        if pin != self.__pin:
            return "PIN码错误"
        if amount <= 0:
            return "取款金额必须大于0"
        if amount > self._balance:
            return "余额不足"
        self._balance -= amount
        return f"取出 {amount},当前余额: {self._balance}"
    
    def get_balance(self, pin):
        if pin == self.__pin:
            return self._balance
        return "PIN码错误"

# 使用示例
account = BankAccount("John Doe", 1000)
print(account.account_holder)  # 公有属性,可以访问
print(account._balance)        # 保护属性,可以访问但不建议
# print(account.__pin)         # 会报错:AttributeError

# 通过方法访问私有属性
print(account.get_balance("1234"))  # 正确方式

# 尝试直接访问私有属性会失败
try:
    print(account.__pin)
except AttributeError as e:
    print(f"错误: {e}")
    # 实际上可以通过名称修饰访问(但不推荐)
    print(f"通过名称修饰访问: {account._BankAccount__pin}")

属性装饰器

Python提供了@property装饰器,可以将方法转换为属性,实现更优雅的封装。

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    
    @property
    def celsius(self):
        """获取摄氏温度"""
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        """设置摄氏温度"""
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        self._celsius = value
    
    @property
    def fahrenheit(self):
        """华氏温度(只读属性)"""
        return (self._celsius * 9/5) + 32
    
    @fahrenheit.setter
    def fahrenheit(self, value):
        """通过华氏温度设置"""
        self.celsius = (value - 32) * 5/9  # 使用celsius的setter

# 使用示例
temp = Temperature(25)
print(f"当前温度: {temp.celsius}°C")  # 使用getter
print(f"华氏温度: {temp.fahrenheit}°F")  # 使用getter

# 修改温度(使用setter)
temp.celsius = 30
print(f"新温度: {temp.celsius}°C")

# 通过华氏温度设置
temp.fahrenheit = 68
print(f"通过68°F设置后: {temp.celsius}°C")

# 尝试设置无效温度
try:
    temp.celsius = -300
except ValueError as e:
    print(f"错误: {e}")

特殊方法(魔术方法)

Python类可以定义特殊方法(以双下划线开头和结尾),这些方法允许类与Python内置函数和操作符交互。

常用特殊方法示例

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    # __str__:定义str()和print()的行为
    def __str__(self):
        return f"Vector({self.x}, {self.y})"
    
    # __repr__:定义repr()和交互式环境中的显示
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"
    
    # __add__:定义+运算符
    def __add__(self, other):
        if isinstance(other, Vector):
            return Vector(self.x + other.x, self.y + other.y)
        return NotImplemented
    
    # __sub__:定义-运算符
    def __sub__(self, other):
        if isinstance(other, Vector):
            return Vector(self.x - other.x, self.y - other.y)
        return NotImplemented
    
    # __mul__:定义*运算符(标量乘法)
    def __mul__(self, scalar):
        if isinstance(scalar, (int, float)):
            return Vector(self.x * scalar, self.y * scalar)
        return NotImplemented
    
    # __rmul__:定义右乘(当乘法顺序反过来时)
    def __rmul__(self, scalar):
        return self.__mul__(scalar)
    
    # __eq__:定义==运算符
    def __eq__(self, other):
        if isinstance(other, Vector):
            return self.x == other.x and self.y == other.y
        return False
    
    # __len__:定义len()函数
    def __len__(self):
        return int((self.x ** 2 + self.y ** 2) ** 0.5)
    
    # __getitem__:定义索引访问
    def __getitem__(self, index):
        if index == 0:
            return self.x
        elif index == 1:
            return self.y
        raise IndexError("Vector index out of range")
    
    # __setitem__:定义索引赋值
    def __setitem__(self, index, value):
        if index == 0:
            self.x = value
        elif index == 1:
            self.y = value
        else:
            raise IndexError("Vector index out of range")

# 使用示例
v1 = Vector(2, 3)
v2 = Vector(1, 4)

print(v1)              # __str__: Vector(2, 3)
print(v1 + v2)         # __add__: Vector(3, 7)
print(v1 * 3)          # __mul__: Vector(6, 9)
print(2 * v1)          # __rmul__: Vector(4, 6)
print(v1 == Vector(2, 3))  # __eq__: True
print(len(v1))         # __len__: 3 (sqrt(2^2+3^2))
print(v1[0], v1[1])    # __getitem__: 2 3
v1[0] = 5              # __setitem__
print(v1)              # Vector(5, 3)

类方法与静态方法

类方法(@classmethod)

类方法的第一个参数是类本身(通常命名为cls),可以访问和修改类状态,但不能访问实例状态。

class Pizza:
    def __init__(self, ingredients, size):
        self.ingredients = ingredients
        self.size = size
    
    def __repr__(self):
        return f"Pizza({self.ingredients}, {self.size})"
    
    @classmethod
    def margherita(cls, size):
        """工厂方法:制作玛格丽特披萨"""
        return cls(["mozzarella", "tomato"], size)
    
    @classmethod
    def pepperoni(cls, size):
        """工厂方法:制作辣香肠披萨"""
        return cls(["mozzarella", "tomato", "pepperoni"], size)
    
    @classmethod
    def get_pizza_info(cls):
        """获取披萨类的信息"""
        return f"我们提供 {cls.__name__},有多种口味可选"

# 使用工厂方法创建披萨
p1 = Pizza.margherita("large")
p2 = Pizza.pepperoni("medium")

print(p1)  # Pizza(['mozzarella', 'tomato'], large)
print(p2)  # Pizza(['mozzarella', 'tomato', 'pepperoni'], medium)
print(Pizza.get_pizza_info())  # 我们提供 Pizza,有多种口味可选

静态方法(@staticmethod)

静态方法既不访问类状态也不访问实例状态,它们只是位于类命名空间中的普通函数。

class MathUtils:
    @staticmethod
    def add(a, b):
        """静态方法:两数相加"""
        return a + b
    
    @staticmethod
    def multiply(a, b):
        """静态方法:两数相乘"""
        return a * b
    
    @staticmethod
    def is_prime(n):
        """静态方法:判断是否为质数"""
        if n <= 1:
            return False
        for i in range(2, int(n ** 0.5) + 1):
            if n % i == 0:
                return False
        return True

# 使用静态方法(无需创建实例)
print(MathUtils.add(5, 3))          # 8
print(MathUtils.multiply(4, 7))     # 28
print(MathUtils.is_prime(17))       # True
print(MathUtils.is_prime(15))       # False

# 也可以通过实例调用
math_utils = MathUtils()
print(math_utils.add(10, 20))       # 30

抽象基类与接口

Python的abc模块提供了定义抽象基类(Abstract Base Class)的工具,用于强制子类实现特定方法。

from abc import ABC, abstractmethod

class PaymentProcessor(ABC):
    """支付处理器的抽象基类"""
    
    @abstractmethod
    def process_payment(self, amount):
        """处理支付,子类必须实现"""
        pass
    
    @abstractmethod
    def refund(self, transaction_id):
        """退款,子类必须实现"""
        pass
    
    def validate_amount(self, amount):
        """非抽象方法,子类可以直接使用"""
        if amount <= 0:
            raise ValueError("金额必须大于0")
        return True

class CreditCardProcessor(PaymentProcessor):
    def __init__(self, merchant_id):
        self.merchant_id = merchant_id
    
    def process_payment(self, amount):
        self.validate_amount(amount)
        # 模拟信用卡处理逻辑
        transaction_id = f"CC-{self.merchant_id}-{int(amount)}"
        print(f"信用卡支付处理成功: 金额={amount}, 交易ID={transaction_id}")
        return transaction_id
    
    def refund(self, transaction_id):
        print(f"信用卡退款处理: 交易ID={transaction_id}")
        return f"REFUND-{transaction_id}"

class PayPalProcessor(PaymentProcessor):
    def __init__(self, email):
        self.email = email
    
    def process_payment(self, amount):
        self.validate_amount(amount)
        # 模拟PayPal处理逻辑
        transaction_id = f"PP-{self.email.split('@')[0]}-{int(amount)}"
        print(f"PayPal支付处理成功: 金额={amount}, 交易ID={transaction_id}")
        return transaction_id
    
    def refund(self, transaction_id):
        print(f"PayPal退款处理: 交易ID={transaction_id}")
        return f"REFUND-{transaction_id}"

# 尝试实例化抽象基类会失败
try:
    base = PaymentProcessor()
except TypeError as e:
    print(f"错误: {e}")

# 正确实例化子类
cc = CreditCardProcessor("M12345")
pp = PayPalProcessor("user@example.com")

# 使用支付处理器
cc.process_payment(100.50)
pp.process_payment(50.25)

# 退款
cc.refund("CC-M12345-100")
pp.refund("PP-user-50")

描述符协议

描述符是实现了描述符协议(__get__, __set__, __delete__)的类,用于自定义属性访问行为。

class TypedProperty:
    """描述符:确保属性值为特定类型"""
    
    def __init__(self, name, expected_type):
        self.name = name
        self.expected_type = expected_type
    
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__.get(self.name)
    
    def __set__(self, instance, value):
        if not isinstance(value, self.expected_type):
            raise TypeError(f"{self.name} 必须是 {self.expected_type.__name__} 类型")
        instance.__dict__[self.name] = value
    
    def __delete__(self, instance):
        raise AttributeError(f"不能删除属性 {self.name}")

class Product:
    # 使用描述符定义属性
    name = TypedProperty("name", str)
    price = TypedProperty("price", (int, float))  # 可以是int或float
    quantity = TypedProperty("quantity", int)
    
    def __init__(self, name, price, quantity):
        self.name = name
        self.price = price
        self.quantity = quantity
    
    def total_value(self):
        return self.price * self.quantity

# 使用示例
try:
    p = Product("Laptop", 999.99, 5)
    print(f"产品: {p.name}, 单价: {p.price}, 数量: {p.quantity}")
    print(f"总价值: {p.total_value()}")
    
    # 尝试设置错误类型
    p.price = "1000"  # 会引发TypeError
    
except TypeError as e:
    print(f"类型错误: {e}")

# 尝试删除属性
try:
    del p.quantity
except AttributeError as e:
    print(f"删除错误: {e}")

设计模式中的OOP应用

单例模式

确保一个类只有一个实例,并提供全局访问点。

import threading

class DatabaseConnection:
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls, *args, **kwargs):
        # 使用双重检查锁定实现线程安全的单例
        if not cls._instance:
            with cls._lock:
                if not cls._instance:
                    cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self, connection_string):
        # 确保初始化只执行一次
        if not hasattr(self, '_initialized'):
            self.connection_string = connection_string
            self.connection = None
            self._initialized = True
    
    def connect(self):
        if not self.connection:
            print(f"连接到数据库: {self.connection_string}")
            self.connection = f"ConnectionObject({self.connection_string})"
        return self.connection
    
    def disconnect(self):
        if self.connection:
            print("断开数据库连接")
            self.connection = None

# 测试单例模式
db1 = DatabaseConnection("mysql://localhost:3306/mydb")
db2 = DatabaseConnection("postgresql://localhost:5432/otherdb")

print(f"db1实例: {id(db1)}")
print(f"db2实例: {id(db2)}")
print(f"是否为同一实例: {db1 is db2}")  # True

db1.connect()
db2.connect()  # 不会创建新连接

# 在多线程环境中测试
def connect_db():
    db = DatabaseConnection("mysql://localhost:3306/mydb")
    db.connect()

threads = []
for _ in range(5):
    t = threading.Thread(target=connect_db)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

观察者模式

定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者都会收到通知。

class Subject:
    """主题(被观察者)"""
    
    def __init__(self):
        self._observers = []
        self._state = None
    
    def attach(self, observer):
        """添加观察者"""
        if observer not in self._observers:
            self._observers.append(observer)
    
    def detach(self, observer):
        """移除观察者"""
        try:
            self._observers.remove(observer)
        except ValueError:
            pass
    
    def notify(self):
        """通知所有观察者"""
        for observer in self._observers:
            observer.update(self)
    
    @property
    def state(self):
        return self._state
    
    @state.setter
    def state(self, value):
        self._state = value
        self.notify()  # 状态改变时通知观察者

class Observer:
    """观察者基类"""
    
    def update(self, subject):
        pass

class NewsAgency(Subject):
    """新闻机构(具体主题)"""
    
    def __init__(self):
        super().__init__()
        self._news = None
    
    @property
    def news(self):
        return self._news
    
    @news.setter
    def news(self, value):
        self._news = value
        self.state = f"新闻更新: {value}"

class Newspaper(Observer):
    """报纸(具体观察者)"""
    
    def __init__(self, name):
        self.name = name
    
    def update(self, subject):
        if isinstance(subject, NewsAgency):
            print(f"{self.name} 收到新闻: {subject.news}")

class TVStation(Observer):
    """电视台(具体观察者)"""
    
    def __init__(self, name):
        self.name = name
    
    def update(self, subject):
        if isinstance(subject, NewsAgency):
            print(f"{self.name} 正在报道: {subject.news}")

# 使用示例
agency = NewsAgency()

# 创建观察者
ny_times = Newspaper("纽约时报")
bbc = TVStation("BBC")
cnn = TVStation("CNN")

# 添加观察者
agency.attach(ny_times)
agency.attach(bbc)
agency.attach(cnn)

# 发布新闻
print("=== 发布第一条新闻 ===")
agency.news = "Python 3.12 发布了!"

# 移除一个观察者
agency.detach(bbc)

# 发布第二条新闻
print("\n=== 发布第二条新闻 ===")
agency.news = "人工智能领域取得新突破"

总结与最佳实践

面向对象设计原则

  1. 单一职责原则(SRP):一个类应该只有一个改变的理由
  2. 开闭原则(OCP):对扩展开放,对修改关闭
  3. 里氏替换原则(LSP):子类应该能够替换父类
  4. 接口隔离原则(ISP):客户端不应该被迫依赖它们不使用的接口
  5. 依赖倒置原则(DIP):依赖抽象而不是具体实现

Python OOP最佳实践

  1. 使用属性装饰器:优先使用@property而不是直接暴露属性
  2. 合理使用继承:避免过深的继承层次,考虑组合优于继承
  3. 文档字符串:为类和方法编写清晰的文档
  4. 类型提示:使用类型注解提高代码可读性和可维护性
  5. 避免魔法方法滥用:只在有意义时使用特殊方法
  6. 保持类的简洁:遵循单一职责原则,避免过大的类
  7. 使用抽象基类定义接口:确保子类实现必要的方法

完整示例:综合应用

from abc import ABC, abstractmethod
from typing import List, Optional
from datetime import datetime

class Notification(ABC):
    """通知的抽象基类"""
    
    @abstractmethod
    def send(self, message: str) -> bool:
        pass

class EmailNotification(Notification):
    def __init__(self, email: str):
        self.email = email
    
    def send(self, message: str) -> bool:
        print(f"发送邮件到 {self.email}: {message}")
        return True

class SMSNotification(Notification):
    def __init__(self, phone: str):
        self.phone = phone
    
    def send(self, message: str) -> bool:
        print(f"发送短信到 {self.phone}: {message}")
        return True

class User:
    """用户类"""
    
    def __init__(self, username: str, email: str, phone: str):
        self.username = username
        self._email = email
        self._phone = phone
        self._notifications: List[Notification] = []
    
    @property
    def email(self) -> str:
        return self._email
    
    @email.setter
    def email(self, value: str):
        if "@" not in value:
            raise ValueError("无效的邮箱格式")
        self._email = value
    
    @property
    def phone(self) -> str:
        return self._phone
    
    @phone.setter
    def phone(self, value: str):
        if not value.isdigit() or len(value) < 10:
            raise ValueError("无效的电话号码")
        self._phone = value
    
    def add_notification(self, notification: Notification):
        self._notifications.append(notification)
    
    def notify_all(self, message: str):
        """发送通知给所有渠道"""
        for notification in self._notifications:
            notification.send(message)

class Order:
    """订单类"""
    
    def __init__(self, order_id: str, user: User, items: List[str]):
        self.order_id = order_id
        self.user = user
        self.items = items
        self.status = "pending"
        self.created_at = datetime.now()
    
    def process(self):
        """处理订单"""
        self.status = "processing"
        self.user.notify_all(f"订单 {self.order_id} 正在处理中")
    
    def complete(self):
        """完成订单"""
        self.status = "completed"
        self.user.notify_all(f"订单 {self.order_id} 已完成")
    
    def cancel(self):
        """取消订单"""
        self.status = "cancelled"
        self.user.notify_all(f"订单 {self.order_id} 已取消")
    
    def __str__(self):
        return (f"订单 {self.order_id} - 用户: {self.user.username}\n"
                f"商品: {', '.join(self.items)}\n"
                f"状态: {self.status}\n"
                f"创建时间: {self.created_at.strftime('%Y-%m-%d %H:%M:%S')}")

# 使用示例
if __name__ == "__main__":
    # 创建用户
    user = User("john_doe", "john@example.com", "13800138000")
    
    # 添加通知渠道
    user.add_notification(EmailNotification(user.email))
    user.add_notification(SMSNotification(user.phone))
    
    # 创建订单
    order = Order("ORD-2023-001", user, ["Python书籍", "键盘"])
    
    # 处理订单
    print("=== 创建订单 ===")
    print(order)
    
    print("\n=== 处理订单 ===")
    order.process()
    
    print("\n=== 完成订单 ===")
    order.complete()
    
    # 测试错误处理
    try:
        user.email = "invalid-email"
    except ValueError as e:
        print(f"\n错误捕获: {e}")

通过这个完整的示例,我们可以看到面向对象编程的各个方面的综合应用:抽象基类定义接口、属性封装、组合模式、事件通知等。这种设计使得代码结构清晰、易于扩展和维护。

结语

面向对象编程是Python的核心特性之一,掌握它对于编写高质量的Python代码至关重要。本文从基础概念到高级应用,详细介绍了Python OOP的各个方面。通过合理运用这些概念和技术,您可以创建出更加模块化、可重用和易于维护的代码。

记住,好的面向对象设计不仅仅是关于语法,更是关于如何将现实世界的问题域有效地映射到代码结构中。持续实践和学习,您将能够更加熟练地运用这些概念来解决复杂的编程问题。