Python面向对象进阶:类的组合详解(组合 vs 继承、代码复用核心)零基础吃透
一、为什么需要「类的组合」?
在面向对象中有两种最核心的代码复用方式:
-
继承(is-a):是什么关系
-
组合(has-a):有什么关系
继承适合:子类是父类的一种(猫是动物、学生是人)
组合适合:一个类包含另一个类的对象(手机有屏幕、人有大脑、电脑有CPU)
面试金句:优先组合,少用继承。 组合耦合度更低、代码更灵活,是实际项目主流写法。
二、什么是类的组合?
2.1 概念定义
类的组合:在一个类中,将另一个类的对象作为自己的属性。
简单理解:一个类包含另一个类,实现功能复用。
2.2 核心关系
继承:is-a 学生 是 人类
组合:has-a 电脑 有 CPU 人 有 身份证 汽车 有 发动机
三、基础组合案例(通俗易懂)
场景:定义 CPU类 和 电脑类,电脑包含CPU
# 子类:CPU类
class Cpu:
def __init__(self, core):
self.core = core # 核心数
def run(self):
print(f"{self.core}核CPU正在高速运行!")
# 主类:电脑类(组合CPU)
class Computer:
def __init__(self, brand, cpu_core):
self.brand = brand
# 将另一个类的对象,作为当前类的属性
self.cpu = Cpu(cpu_core)
def start(self):
print(f"{self.brand} 电脑开机")
# 调用组合对象的方法
self.cpu.run()
# 测试
pc = Computer("联想", 8)
pc.start()
运行结果
联想 电脑开机
8核CPU正在高速运行!
代码解析
Computer 类中并没有写 CPU 相关代码,直接组合 Cpu 对象,实现功能复用。
优点:CPU类可以单独维护、单独修改、多次复用。
四、进阶案例:多人组合场景
场景:每个人拥有一个身份证,多人可以复用身份证类
# 身份证类
class IdCard:
def __init__(self, id_num, address):
self.id_num = id_num
self.address = address
def show_id(self):
print(f"身份证号:{self.id_num},地址:{self.address}")
# 人类(组合身份证)
class Person:
def __init__(self, name, age, id_obj):
self.name = name
self.age = age
# 组合:传入IdCard对象
self.id_card = id_obj
def show_info(self):
print(f"姓名:{self.name},年龄:{self.age}")
self.id_card.show_id()
# 测试:两个不同的人,组合各自的身份证
card1 = IdCard("110101200001011234", "北京市")
p1 = Person("张三", 20, card1)
card2 = IdCard("310101199902024567", "上海市")
p2 = Person("李四", 22, card2)
p1.show_info()
print("-" * 40)
p2.show_info()
五、组合的优势:低耦合、高复用
如果用继承实现上面的案例
人继承身份证 → 逻辑错误,人不是身份证,强行继承会造成语义混乱。
组合完美解决
语义正确:人 有 身份证
代码解耦:身份证类和人类互不干涉
灵活替换:可以随时更换 CPU、更换身份证对象
六、组合 vs 继承(超清晰对比)
|
对比项 |
继承(extends) |
组合(composition) |
|---|---|---|
|
关系 |
is-a 是什么 |
has-a 有什么 |
|
耦合度 |
高(父子强依赖) |
低(独立模块) |
|
灵活性 |
差,固定继承 |
高,可动态替换对象 |
|
使用场景 |
层级体系、从属关系 |
部件组装、功能复用七、动态组合(高阶写法) |
七、动态组合(高阶写法)
不用在构造方法固定传入,可以动态绑定组件,灵活性拉满。
class Battery:
def power(self):
print("电池供电中...")
class Phone:
def __init__(self, name):
self.name = name
self.battery = None # 先空着
# 动态组合
def set_battery(self, bat_obj):
self.battery = bat_obj
def work(self):
if self.battery:
self.battery.power()
print(f"{self.name} 正常工作")
# 动态装配电池
p = Phone("华为手机")
b = Battery()
p.set_battery(b)
p.work()
八、常见面试题总结
1. 什么是组合?
在一个类中包含另一个类的实例对象作为属性,用来实现代码复用,属于 has-a 关系。
2. 组合和继承哪个好?
组合更好,耦合更低、扩展性更强、符合设计模式思想。
3. 什么时候用组合?
当两个类是 包含、组件、附属 关系时,一律用组合。
九、全文总结
-
组合是 has-a 包含关系,继承是 is-a 从属关系;
-
组合:将一个类的对象作为另一个类的属性;
-
组合代码解耦、灵活、可单独维护组件;
-
项目开发优先使用组合,避免过度继承导致代码僵化。
✨ 点赞收藏,OOP三大核心:封装、继承、组合 全部学完!
更多推荐



所有评论(0)