首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
第 13章 性能测量和大O算法分析
13.1 timeit模块
13.2 cProfile分析器
13.3 大O算法分析
13.4 大O阶
13.4.1 使用书架打比方描述大O阶
13.4.2 大O 测量的是最坏情况
13.5 确定代码的大O 阶
13.5.1 为什么低阶项和系数不重要
13.5.2 大O 分析实例
13.5.3 常见函数调用的大O 阶
13.5.4 一眼看出大O 阶
13.5.5 当n 很小时,大O并不重要,而n通常都很小
第 14章 项目实战
14.1 汉诺塔
14.1.1 汉诺塔输出
14.1.2 汉诺塔源代码
14.1.3 汉诺塔编写代码
14.2 四子棋
14.2.1 四子棋输出
14.2.2 四子棋源代码
14.2.3 四子棋编写代码
第 15章 面向对象编程和类
15.1 拿现实世界打比方:填写表格
15.2 基于类创建对象
15.3 创建一个简单的类——WizCoin
15.3.1 方法__init__()和self
15.3.2 特性
15.3.3 私有特性和私有方法
15.4 函数type()和特性__qualname__
15.5 非OOP 和OOP 的例子:井字棋
15.6 为现实世界设计类是一件难事儿
第 16章 面向对象编程和继承
16.1 继承的原理
16.1.1 重写方法
16.1.2 super()函数
16.1.3 倾向于组合而非继承
16.1.4 继承的缺点
16.2 函数isinstance()和issubclass()
16.3 类方法
16.4 类特性
16.5 静态方法
16.6 何时应该使用类和静态的面向对象特性
16.7 面向对象的行话
16.7.1 封装
16.7.2 多态性
16.8 何时不应该使用继承
16.9 多重继承
16.10 方法解析顺序
第 17章 Python 风格的面向对象编程:属性和魔术方法
17.1 属性
17.1.1 将特性转换为属性
17.1.2 使用setter 验证数据
17.1.3 只读属性
17.1.4 什么时候应该使用属性
17.2 Python 的魔术方法
17.2.1 字符串表示魔术方法
17.2.2 数值魔术方法
17.2.3 反射数值魔术方法
17.2.4 原地魔术方法
17.2.5 比较魔术方法
当前位置:
首页>>
技术小册>>
Python编程轻松进阶(五)
小册名称:Python编程轻松进阶(五)
### 16.1.3 倾向于组合而非继承 在Python编程的广阔天地中,面向对象编程(OOP)是构建复杂系统、提高代码复用性和可维护性的重要基石。在OOP的众多原则中,“倾向于组合而非继承”是一条既深刻又实用的设计原则,它指导我们在设计类结构时如何更加灵活和高效地利用代码资源。本章节将深入探讨这一原则的含义、优势、应用场景以及如何在实践中正确应用。 #### 1. 理解原则本质 首先,我们需要明确“组合”与“继承”的基本概念。 - **继承**:是一种基于类之间“是一个”(is-a)关系的代码复用方式。子类继承父类的属性和方法,并可以添加或覆盖(重写)这些方法。继承使得代码结构具有层次性,但同时也可能引入紧耦合和复杂的继承链问题。 - **组合**:则是通过将一个对象作为另一个对象的属性来实现代码复用。这种方式体现了“有一个”(has-a)的关系。组合使得类之间的关系更加灵活,易于理解和维护,同时也降低了系统各部分的耦合度。 “倾向于组合而非继承”的原则强调,在大多数情况下,通过组合来复用代码比直接使用继承更为可取。这是因为组合提供了更高的灵活性和更低的耦合度,使得系统更加容易扩展和维护。 #### 2. 组合的优势 - **灵活性**:组合允许我们在运行时动态地改变对象的行为,而继承则是静态的,一旦继承关系确定,就很难在不修改类定义的情况下改变行为。 - **低耦合**:组合减少了类之间的直接依赖,降低了系统的耦合度。当系统需要变化时,只需要修改组合中的某个部分,而不需要修改整个继承体系。 - **易于理解和测试**:组合使得类的职责更加单一,易于理解和测试。每个类都专注于自己的职责,而不是承担从父类继承而来的额外负担。 - **代码复用**:虽然继承也提供了代码复用的手段,但组合通常能提供更细粒度的复用方式。我们可以根据需要选择性地复用某个类的功能,而不是继承整个类。 #### 3. 应用场景 - **当存在“有一个”关系时**:如果两个类之间存在“有一个”的关系,即一个类是另一个类的组成部分,那么应该使用组合而非继承。例如,一个`Car`类有一个`Engine`对象,而不是继承自`Engine`类。 - **需要动态行为时**:如果我们需要根据运行时的情况动态地改变对象的行为,那么组合是一个更好的选择。因为继承的行为是静态的,在编译时就已确定。 - **避免复杂继承体系**:当继承体系变得复杂时,维护和理解起来会非常困难。使用组合可以避免这种情况,将复杂的功能分解为更小的、更易于管理的部分。 - **实现接口或行为复用**:虽然Python中没有像Java那样的接口关键字,但我们可以通过组合来模拟接口的行为复用。即,定义一个包含抽象方法的类作为接口,然后通过组合将这些方法实现到具体的类中。 #### 4. 实践中的考虑 - **合理使用继承**:虽然倾向于组合,但并不意味着完全摒弃继承。在某些情况下,如实现多态或共享一些公共的属性和方法时,继承仍然是非常有用的。关键是要根据具体情况选择合适的复用方式。 - **封装和接口**:无论使用组合还是继承,都应该注重封装和接口的设计。良好的封装可以隐藏类的内部实现细节,只暴露必要的接口给外部使用。这有助于提高系统的可维护性和可扩展性。 - **测试和维护**:在使用组合时,要注意对组合中的每个对象进行充分的测试,以确保它们的行为符合预期。同时,也要关注系统的整体结构和维护成本,确保组合的使用不会增加系统的复杂性。 #### 5. 案例分析 假设我们正在设计一个游戏系统,其中包含了多个角色和武器。每个角色都可以装备不同的武器,并且每种武器都有其特定的攻击效果。在这个场景下,我们可以考虑使用组合来实现角色和武器之间的关系。 首先,我们定义一个`Weapon`基类,它包含一些基本的属性和方法,如攻击力、攻击速度等。然后,我们定义多个具体的武器类(如`Sword`、`Bow`等),它们继承自`Weapon`类并实现特定的攻击逻辑。 接着,我们定义一个`Character`类,它包含一个`Weapon`类型的属性来表示角色当前装备的武器。`Character`类还包含一些与角色相关的方法,如移动、攻击等。在攻击方法中,我们可以调用武器对象的攻击方法来实现具体的攻击行为。 通过这种方式,我们既实现了代码的复用(通过继承`Weapon`类),又保持了系统的灵活性(通过组合将武器与角色关联起来)。当需要添加新的武器或角色时,我们只需要创建新的类并适当地组合它们即可,而无需修改现有的类结构。 #### 6. 总结 “倾向于组合而非继承”是面向对象编程中一条非常重要的设计原则。它鼓励我们在设计类结构时优先考虑组合的方式来实现代码复用和功能扩展。通过合理使用组合和继承,我们可以构建出更加灵活、易于理解和维护的Python程序。在实践中,我们应该根据具体情况选择合适的复用方式,并注重封装和接口的设计,以确保系统的稳定性和可扩展性。
上一篇:
16.1.2 super()函数
下一篇:
16.1.4 继承的缺点
该分类下的相关小册推荐:
Python编程轻松进阶(二)
Python机器学习基础教程(下)
Python数据分析与挖掘实战(下)
Python编程轻松进阶(四)
Python机器学习实战
Python高并发编程与实战
机器学习算法原理与实战
Python合辑9-判断和循环
Python合辑10-函数
Python合辑8-变量和运算符
Python合辑4-130个字符串操作示例
Python爬虫入门与实战开发(上)