
一、开篇继承不是万能的继承是OOP中最常用的代码复用方式——但也有继承滥用的问题。当你用继承只是为了复用代码而不是真的is-a关系或者继承层次越来越深三层、四层…就到了重新审视设计的时候。⌨️ 先看一个典型的问题场景# ❌ 继承的误用——为了代码复用而继承classVehicle:defmove(self):return移动中classCar(Vehicle):# 汽车是交通工具 ✓passclassAirplane(Vehicle):# 飞机是交通工具 ✓passclassBoat(Vehicle):# 船是交通工具 ✓pass# 问题来了两栖车怎么办classAmphibiousCar(Car,Boat):# 多重继承复杂度爆炸pass# 能飞的车呢# class FlyingCar(Car, Airplane): ... # 菱形继承的噩梦组合提供了一种更灵活的思路把能力封装成独立的对象然后组装到类中——而不是通过继承来获得。二、组合的基本模式2.1 用属性持有功能对象# ✅ 组合方式——将能力封装为独立类通过属性持有classEngine:引擎——独立的功能组件def__init__(self,horsepower):self.horsepowerhorsepowerdefstart(self):returnf引擎({self.horsepower}马力)启动defstop(self):return引擎停止classWheels:轮子——独立组件def__init__(self,count4):self.countcountdefroll(self):returnf{self.count}个轮子转动中classGPS:GPS导航——独立组件defnavigate(self,destination):returnf导航到{destination}classCar:汽车——通过组合拥有引擎、轮子、GPSdef__init__(self,brand,horsepower):self.brandbrand self.engineEngine(horsepower)# 组合Car有一个引擎self.wheelsWheels(4)# 组合Car有4个轮子self.gpsNone# 可选组件definstall_gps(self):self.gpsGPS()defstart(self):returnf{self.brand}:{self.engine.start()}defdrive_to(self,destination):actionf{self.start()},{self.wheels.roll()}ifself.gps:actionf,{self.gps.navigate(destination)}returnaction# 使用——灵活组装carCar(丰田,150)print(car.start())# 丰田: 引擎(150马力)启动print(car.drive_to(北京))# 丰田: 引擎(150马力)启动, 4个轮子转动中car.install_gps()print(car.drive_to(天安门))# 丰田: 引擎(150马力)启动, 4个轮子转动中, 导航到天安门# 与继承对比# 继承Car is-a Vehicle —— 关系固定# 组合Car has-a Engine —— 关系灵活随时替换2.2 组件可替换# 组合的伟大之处——运行时替换组件classElectricEngine:电动引擎def__init__(self,power):self.powerpowerdefstart(self):returnf电动机({self.power}kW)无声启动defstop(self):return电动机停止classCar:def__init__(self,brand):self.brandbrand self.engineNonedefset_engine(self,engine):self.engineenginedefstart(self):ifself.engineisNone:return没有引擎returnf{self.brand}:{self.engine.start()}# 同一辆车——可以换不同引擎carCar(特斯拉)car.set_engine(ElectricEngine(250))print(car.start())# 特斯拉: 电动机(250kW)无声启动car.set_engine(Engine(200))# 换成燃油引擎print(car.start())# 特斯拉: 引擎(200马力)启动# 这在继承中是不可能的——一旦定义了继承关系就固定了三、实战对比继承 vs 组合3.1 用继承实现员工系统问题版# ❌ 继承地狱——不同维度的功能通过多层继承实现classEmployee:def__init__(self,name,salary):self.namename self.salarysalarydefwork(self):return工作中classDeveloper(Employee):defwork(self):return写代码classManager(Employee):defwork(self):return管理团队# 如果需要会Python的远程工作管理者# class RemotePythonManager(Manager, PythonDeveloper, RemoteWorker):# pass # 多重继承MRO噩梦3.2 用组合重构优雅版# ✅ 组合——每个维度独立封装classEmployee:员工——核心类def__init__(self,name,salary):self.namename self.salarysalary self.roleNone# 角色组合self.work_styleNone# 工作方式组合self.skills[]# 技能列表组合defset_role(self,role):self.roleroledefset_work_style(self,style):self.work_stylestyledefadd_skill(self,skill):self.skills.append(skill)defwork(self):actions[]ifself.role:actions.append(self.role.perform())ifself.work_style:actions.append(self.work_style.apply())ifself.skills:actions.append(使用技能: , .join(s.nameforsinself.skills))return | .join(actions)ifactionselse无任务# 角色组件classDeveloperRole:defperform(self):return编写代码和进行代码审查classManagerRole:defperform(self):return管理团队和制定计划# 工作方式组件classRemoteWork:defapply(self):return远程办公在家工作classOfficeWork:defapply(self):return办公室办公# 技能组件classSkill:def__init__(self,name,level):self.namename self.levellevel# 使用——灵活组合employeeEmployee(张三,20000)employee.set_role(DeveloperRole())# 角色开发者employee.set_work_style(RemoteWork())# 方式远程employee.add_skill(Skill(Python,高级))employee.add_skill(Skill(Django,中级))print(f{employee.name}:{employee.work()})# 张三: 编写代码和进行代码审查 | 远程办公在家工作 | 使用技能: Python, Django# 轻松切换到管理者办公室employee.set_role(ManagerRole())employee.set_work_style(OfficeWork())print(f{employee.name}:{employee.work()})# 张三: 管理团队和制定计划 | 办公室办公 | 使用技能: Python, Django四、什么时候用什么样# ✅ 用继承真正的is-a关系classAnimal:passclassDog(Animal):pass# 狗是动物 ✓classCat(Animal):pass# 猫是动物 ✓# 继承适合# - 明确的层级关系猫是动物# - 需要多态同一接口不同实现# - 不需要运行时替换行为# - 层级不深1-2层# ✅ 用组合has-a关系classCar:def__init__(self):self.engineEngine()# 车有引擎self.wheelsWheels()# 车有轮子# 组合适合# - 需要运行时替换组件# - 多维度功能组合角色方式技能# - 避免深层继承# - 需要对调用者隐藏复杂度# 组合接口ABC 最灵活的设计fromabcimportABC,abstractmethodclassPaymentMethod(ABC):abstractmethoddefpay(self,amount):passclassOrder:订单——通过组合持有支付方式def__init__(self,amount,payment_method:PaymentMethod):self.amountamount self.payment_methodpayment_method# 组合defcheckout(self):returnself.payment_method.pay(self.amount)五、总结“组合优于继承不是否定继承的价值而是提醒你继承是最强的耦合”用之前先想想能否用更灵活的组合。核心要点继承 “is-a”狗是动物 → 适合继承组合 “has-a”车有引擎 → 适合组合组合更灵活运行时替换、多维度组合继承更简单代码自动获得、免费的多态两者结合使用ABC定义接口 组合注入实现✅每当你准备写class SubClass(ParentClass)时停下来问自己SubClass真的是ParentClass的一种吗如果不是——用组合。