副标题 / 摘要
继承容易让系统变脆,组合让系统更灵活。本文解释为什么组合更适合工程演进,并给出实用示例。
目标读者
- 写面向对象代码的工程师
- 负责模块演进与重构的开发者
- 做代码评审与架构设计的团队
背景 / 动机
继承会把父类的实现细节暴露给子类,容易导致“脆弱基类问题”。
组合通过“把能力作为对象注入”来降低耦合,更易测试与替换。
核心概念
- 继承(Inheritance):is-a 关系,强耦合
- 组合(Composition):has-a 关系,弱耦合
- 脆弱基类问题:父类改动导致子类行为改变
实践指南 / 步骤
- 优先建接口,延后继承
- 把可变行为抽成组件
- 用组合注入行为
- 通过依赖替换实现测试
- 只在“稳定共性”时使用继承
可运行示例
class Logger:
def log(self, msg: str) -> None:
print(msg)
class FileSaver:
def save(self, data: str) -> None:
print("save", data)
class ReportService:
def __init__(self, logger: Logger, saver: FileSaver):
self.logger = logger
self.saver = saver
def run(self, data: str) -> None:
self.logger.log("start")
self.saver.save(data)
self.logger.log("done")
if __name__ == "__main__":
svc = ReportService(Logger(), FileSaver())
svc.run("report")
解释与原理
组合让行为可替换(如 Logger 可以换成 Mock)。
继承则把依赖固定在父类上,一旦父类变化,子类难以控制影响。
常见问题与注意事项
继承是不是完全不好?
不是,稳定领域模型可以使用继承。组合会不会更啰嗦?
会多一些对象,但换来可测试性与灵活性。什么时候适合继承?
当“is-a”关系稳定且不会频繁变更。
最佳实践与建议
- 可变行为优先组合
- 继承只用于稳定抽象
- 把依赖注入作为默认模式
小结 / 结论
组合减少耦合、提升可测试性,是更适合工程演进的方式。
继承应谨慎使用,只在稳定抽象场景下采用。
参考与延伸阅读
- Design Patterns(GoF)
- Refactoring(Martin Fowler)
元信息
- 阅读时长:7~9 分钟
- 标签:组合、继承、设计模式
- SEO 关键词:Composition, Inheritance
- 元描述:解释为何组合优于继承,并给出工程实践。
行动号召(CTA)
找一个继承层级复杂的模块,尝试用组合重构,你会看到可维护性提升。