OOP 基础知识:组合(设计)
使用 OOP 进行程序设计时,存在一个问题,即根据某些给定的特征,找到最佳的类划分方法以及类之间的关系。“组合”一词可能存在歧义,并且经常用于表示不同的含义,包括对类“进行组合”的特殊情况。之所以要稍微离题一下,是因为在阅读其他计算机方面的文献时,您会发现对“组合”一词有不同的解释:既有广义的,也有狭义的。我们将尝试解释这个概念,并具体说明每个情况下这些术语的含义(当它表示软件界面的一般“设计/项目开发”时,以及当它表示“组合聚合”时)。
我们已经知道,类由字段(属性)和方法组成。属性反过来可以用自定义类型来描述,也就是说,它们可以是另一个类的对象。有几种方法可以逻辑方式连接这些对象:
- 将对象字段组合 (完全 纳入 或组合聚合)到所有者对象中。这些对象之间的关系可通过“整体-部分”关系描述,部分不能存在于整体之外。可以说所有者对象“拥有”属性对象,而属性对象是所有者对象的“一部分”。所有者创建并销毁其部分。删除所有者会移除其所有部分;所有者不能脱离部分而存在。
- 聚合 所有者对象对对象字段的聚合是一种“更软”的包含关系。虽然这种关系也被描述为“整体-部分”,但所有者仅包含对可赋值、可更改且独立于整体存在的部分的引用。此外,一个部分可以被多个“所有者”使用。
- 关联,即独立对象之间的单向或双向连接,连接的含义可以任意规定;可以说一个对象“使用”另一个对象。
另一种需要记住的关系类型是“是 (is a)”,我们在前面的 继承 一节讨论过。
完全包含的一个例子是汽车及其发动机。在这里,汽车被理解为一种功能齐全的交通工具。没有发动机的汽车显然不是。并且一个特定的发动机一次只能属于一辆汽车。当汽车中还没有发动机(在工厂)或发动机不再存在(在汽车修理厂)时,相当于我们破坏了程序的源代码。
聚合的一个例子是一起学习某些课程的学生小组:每门课程的小组包含多名学生,其中任何学生都可以属于其他小组(如果同时学习多个科目)。该小组“拥有”听众。一名学生退出小组不会影响小组的学习进程(其余学生将继续学习)。
最后,为了演示关联的概念,我们设想一台计算机和一台打印机。我们可以说计算机使用打印机进行打印。打印机可以根据需要打开或关闭,并且同一台打印机可以在不同的计算机上使用。所有计算机和打印机彼此独立存在,但可以共享。
至于通常用于指导类设计的特征,最著名的包括:
- DRY(不要重复自己):将公共部分移到父类(可能是抽象类)中。
- SRP(单一职责原则)―一个类应该执行一项任务,如果不是这样,则需要将其拆分为更小的类。
- OCP(开放-封闭原则)―“编写的代码可以扩展但不能被修改”。如果 X 类中硬编码了多个计算选项,并且可能出现新的计算选项,则为单独的计算创建一个基类(抽象类),在其基础上创建特定选项(功能的“扩展”),并将其连接到类 X 而不进行修改。
这些只是类设计最佳实践中的一小部分。在掌握本书范围内的 OOP 基础知识之后,浏览其他关于该主题的专业信息来源可能也会对您有所帮助,因为它们为许多常见情况下的对象分解提供了现成的解决方案。