组合与继承的对比
本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 56 课,共 91 课。
在上一章中,你学到 trait 提供“拥有”能力,而继承则建立“是”关系。组合进一步运用“拥有”这一概念,通过简单对象构建复杂对象,并将简单对象存储为属性,而不是继承它们。
通过继承,Car 可以扩展 Vehicle。通过组合,Car 包含 一个 Engine 对象:
<?php
class Engine {
public function start(): string {
return "Engine started";
}
}
class Car {
private Engine $engine;
public function __construct() {
$this->engine = new Engine();
}
public function start(): string {
return $this->engine->start();
}
}
$car = new Car();
echo $car->start();
输出:
Engine startedCar 类不继承自 Engine,而是拥有一个 Engine。这种方式有明显的优势:你可以换用另一种实现的引擎,类之间保持松散耦合,还能避免深层继承造成的僵化层级结构。
面向对象编程中的一条常见准则是“优先使用组合,而不是继承。”对于真正的类型层次结构,继承很适用(Dog 确实是 Animal),但如果要用独立的部分组装功能,组合就更有优势。你可以组合多个对象,在运行时替换它们,并单独测试各个组件。
下一课将介绍依赖注入。依赖注入建立在组合的基础上,通过控制对象获取依赖项的方式来实现。
挑战
简单让我们使用组合来构建一个计算机系统,其中 Computer 由单独的组件对象组装而成,而不是通过继承这些组件来构建。这展示了组合如何让你用简单、独立的部分构建复杂对象。
你要把代码组织到 3 个文件中:
Processor.php:创建一个表示 CPU 的Processor类。使用构造函数属性提升来定义私有的$model(字符串)和私有的$cores(整数)。添加一个getSpecs()方法,返回"[model] ([cores] cores)"。Memory.php:创建一个表示 RAM 的Memory类。使用构造函数属性提升来定义私有的$size(表示 GB 的整数)。添加一个getCapacity()方法,返回"[size]GB RAM"。main.php:引入这两个组件文件,并创建一个使用组合的Computer类。Computer应该:- 将一个
Processor对象和一个Memory对象存储为私有属性 - 在构造函数中接收处理器型号、核心数和内存大小
- 在构造过程中于内部创建组件对象
- 包含一个
describe()方法,返回"Computer with [processor specs] and [memory capacity]"
你会收到 3 项输入:处理器型号、核心数和以 GB 为单位的内存大小。使用这些规格创建一个
Computer,并打印调用describe()的结果。- 将一个
注意,Computer 并没有继承 Processor 或 Memory。它是“包含”它们。通过组合建立的这种“拥有”关系,让每个组件保持独立且可复用,同时也允许 Computer 在需要时将任务委托给它的组成部分。
亲手试试
<?php
require_once 'Processor.php';
require_once 'Memory.php';
class Computer
{
// TODO: 定义私有属性,用于存储 Processor 和 Memory 对象
// TODO: 构造函数应接收处理器型号、核心数和内存大小
// 并在内部创建组件对象
public function __construct()
{
// TODO: 创建 Processor 和 Memory 对象并存储它们
}
// TODO: 实现 describe() 方法,使其返回
// "Computer with [processor specs] and [memory capacity]"
public function describe(): string
{
// TODO: 调用组件对象的方法并返回格式化后的字符串
}
}
// 读取输入
$processorModel = trim(fgets(STDIN));
$cores = intval(fgets(STDIN));
$memorySize = intval(fgets(STDIN));
// TODO: 根据给定的规格创建 Computer 对象,并打印 describe() 的结果
?>这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: PHP 在线编译器