在Python面向对象编程中,组合(Composition)是一种"has-a"的关系实现方式。与继承不同,组合通过在类中嵌入其他类的实例来实现功能复用。这种设计模式更符合"组合优于继承"的原则,能有效避免继承带来的紧耦合问题。
继承(is-a)和组合(has-a)是两种主要的代码复用方式。继承适合表达"是一个"的关系,如"猫是动物";而组合适合表达"有一个"的关系,如"汽车有发动机"。实际开发中,组合通常更灵活:
python复制# 继承实现
class Engine:
pass
class Car(Engine): # 不合理的继承
pass
# 组合实现
class Car:
def __init__(self):
self.engine = Engine() # 合理的组合
组合的优势在于:
组合模式特别适合以下场景:
实际案例:构建一个计算机系统模拟
python复制class CPU:
def process(self):
print("CPU processing data")
class Memory:
def store(self):
print("Memory storing data")
class Computer:
def __init__(self):
self.cpu = CPU()
self.memory = Memory()
def run(self):
self.cpu.process()
self.memory.store()
提示:当发现继承层次超过3层时,应考虑是否能用组合重构
Python中的方法根据绑定方式和调用方式不同,可分为实例方法、类方法和静态方法三种,它们在使用场景和实现原理上有显著差异。
实例方法是最常见的方法类型,第一个参数固定为self,指向调用该方法的实例:
python复制class MyClass:
def instance_method(self, arg):
print(f"Called instance_method with {self} and {arg}")
obj = MyClass()
obj.instance_method("test") # 自动传入self
关键特点:
类方法使用@classmethod装饰器定义,第一个参数固定为cls,指向类本身:
python复制class MyClass:
@classmethod
def class_method(cls, arg):
print(f"Called class_method with {cls} and {arg}")
MyClass.class_method("test") # 也可以通过实例调用
典型应用场景:
工厂模式示例:
python复制class Person:
def __init__(self, name):
self.name = name
@classmethod
def from_json(cls, json_data):
return cls(json_data["name"])
静态方法使用@staticmethod装饰器定义,没有默认的self或cls参数:
python复制class MyClass:
@staticmethod
def static_method(arg):
print(f"Called static_method with {arg}")
MyClass.static_method("test") # 实例也可调用
适用情况:
注意:过度使用静态方法可能是设计问题的信号,应考虑是否真的属于该类
装饰器是Python中最强大的特性之一,本质上是一个可调用对象,用于修改或增强其他函数或类的行为。
最简单的装饰器形式是一个接受函数作为参数并返回新函数的函数:
python复制def simple_decorator(func):
def wrapper(*args, **kwargs):
print(f"Before calling {func.__name__}")
result = func(*args, **kwargs)
print(f"After calling {func.__name__}")
return result
return wrapper
@simple_decorator
def say_hello(name):
print(f"Hello, {name}!")
装饰器执行流程:
通过嵌套函数可以实现接受参数的装饰器:
python复制def repeat(num_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(num_times=3)
def greet(name):
print(f"Hello {name}")
这种模式常用于:
装饰器不仅可以装饰函数,也可以装饰类。同时,类也可以作为装饰器:
python复制# 类装饰器
def add_method(cls):
cls.new_method = lambda self: print("Added method")
return cls
@add_method
class MyClass:
pass
# 装饰器类
class Timer:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
start = time.time()
result = self.func(*args, **kwargs)
print(f"Elapsed: {time.time() - start}")
return result
@Timer
def long_running_func():
time.sleep(1)
多个装饰器可以堆叠使用,执行顺序从下往上:
python复制@decorator1
@decorator2
@decorator3
def func():
pass
# 等价于:decorator1(decorator2(decorator3(func)))
实际应用中的常见组合:
结合组合、方法和装饰器可以构建灵活的设计模式实现。
使用组合和类方法实现策略模式:
python复制class PaymentStrategy:
@classmethod
def pay(cls, amount):
raise NotImplementedError
class CreditCardPayment(PaymentStrategy):
@classmethod
def pay(cls, amount):
print(f"Paying {amount} via Credit Card")
class PayPalPayment(PaymentStrategy):
@classmethod
def pay(cls, amount):
print(f"Paying {amount} via PayPal")
class Order:
def __init__(self, payment_strategy):
self._payment_strategy = payment_strategy
def process_payment(self, amount):
self._payment_strategy.pay(amount)
使用装饰器简化观察者模式实现:
python复制class EventSystem:
_observers = {}
@classmethod
def register(cls, event_type):
def decorator(func):
if event_type not in cls._observers:
cls._observers[event_type] = []
cls._observers[event_type].append(func)
return func
return decorator
@classmethod
def notify(cls, event_type, *args, **kwargs):
for observer in cls._observers.get(event_type, []):
observer(*args, **kwargs)
@EventSystem.register("login")
def on_login(user):
print(f"{user} logged in")
EventSystem.notify("login", "Alice")
构建灵活的游戏装备系统:
python复制class Equipment:
def __init__(self):
self._stats = {}
def stat_bonus(self, stat):
return self._stats.get(stat, 0)
def stat_modifier(stat, amount):
def decorator(cls):
original_init = cls.__init__
def __init__(self, *args, **kwargs):
original_init(self, *args, **kwargs)
self._stats[stat] = self._stats.get(stat, 0) + amount
cls.__init__ = __init__
return cls
return decorator
@stat_modifier("attack", 5)
class Sword(Equipment):
def __init__(self):
super().__init__()
self._stats["attack"] = 10
@stat_modifier("defense", 3)
class Shield(Equipment):
def __init__(self):
super().__init__()
self._stats["defense"] = 5
方法调用在Python中会产生一定的开销:
在性能关键路径上:
装饰器会隐藏原函数的元信息,使用functools.wraps保持原信息:
python复制from functools import wraps
def debug_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
调试工具:
组合中的组件生命周期需要特别注意:
python复制from weakref import ref
class Parent:
def __init__(self):
self.child = Child(self) # 强引用导致循环
class Child:
def __init__(self, parent):
self.parent = ref(parent) # 使用弱引用打破循环
常见反模式及修正方案:
误将工具函数定义为实例方法:
滥用类方法作为工厂:
装饰器副作用不可控: