type
Post
status
Published
date
Feb 26, 2026
slug
summary
tags
虚幻
思考
编程
category
学习笔记
comment
Show
icon
password
遵守“Is-A(是一个)”vs“Has-A(有一个)”法则——面向对象编程中的一条基础设计原则
核心概念对比:“Has-A” vs “Is-A”
“Has-A”(有一个)—— 组合
含义:新对象把老对象作为自己的一个“零件”或“属性”装配进来。比如:电脑有一个CPU,电脑有一个打印机。
特点:把任务委托给更专业的部分去完成。
“Is-A”(是一个)—— 继承
含义:子类完全继承父类的基因,是父类的一种特殊形态。比如:苹果是一个水果,汽车是一个交通工具。
特点:子类自动获得父类的所有非私有属性和方法。
组合和继承的优劣
对比维度 | “Has-A”(组合/聚合)✅推荐 | “Is-A”(继承)⚠️需谨慎 |
复用类型 | 黑箱复用:不需要知道内部细节,只管调用接口。 | 白箱复用:破坏了封装,父类内部细节对子类暴露无遗。 |
耦合度 | 低:依赖较少,一个零件坏了换一个即可。 | 高:父类一旦修改,所有子类都可能受到牵连(牵一发而动全身)。 |
灵活性 | 动态(运行时):可以在程序运行时动态更换或添加零件。 | 静态(编译时):关系在写代码时就锁死了,无法在运行中改变。 |
缺点 | 需要管理的对象数量可能会变多。 | 极易被滥用,增加系统复杂度和维护难度。 |
什么时候用“继承”
继承固然强大,但是滥用的副作用也不容小觑,使用时应遵守Coad法则,只有当同时满足以下条件时,才应该使用继承(Is-A):
- 真的是同类:子类必须是父类的“一种特殊种类”,而不是父类的“一个角色”。
- 不频繁换爹:子类将来不会变成其他类的子类。
- 只做加法:子类是为了扩展父类的功能,而不是大量推翻重写(置换)父类的功能。
- 有现实意义:在现实世界的分类学上是讲得通的(不要仅仅为了借用某个工具类的方法而去继承它)。
经典实际案例:角色陷阱
人们经常犯的错误是把“角色”(Has-A)当成了“种类”(Is-A)。
- ❌ 错误设计(滥用继承):把“人”作为父类,“经理”、“雇员”、“学生”作为子类。
- 矛盾点:这是一种“Is-A”设计。如果一个人既是雇员又是学生呢?如果他升职成了经理呢?由于继承是静态排他的,这种设计会直接崩溃。

- ✅ 正确设计(使用组合/聚合):创建一个“角色”类(包含经理、雇员等子类),然后让“人”拥有(Has-A)多个“角色”。
- 优势:一个人可以动态地添加、删除不同的角色,完美契合现实逻辑。

总结:
当复用代码时,先考虑:这两个类到底是“A包含B(Has-A)”还是“A本质上就是B(Is-A)”?如果是前者,果断用组合;即使是后者,也要慎重评估是否会带来高耦合。
📎 参考文章
- 作者:LiQingBa
- 链接:https://blog.liqingba.com/article/313a69f5-f1f3-8069-9be4-e8f97944f7bf
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
