本文目录导读:

是的,模板方法模式(Template Method Pattern)的核心目的就是定义一个操作中的算法骨架,而将一些具体步骤的实现延迟到子类中。
在 PHP 中,这个模式非常常用,尤其是当多个子类有相同的处理流程,但某些步骤的具体实现不同时。
核心定义(与你的问题直接相关)
模板方法模式通过一个 “模板方法” 来定义算法的骨架。
- 骨架(Skeleton):指的是一个固定的、不可更改的执行顺序。
步骤A -> 步骤B -> 步骤C,这个顺序在父类的模板方法中已经写死。 - 具体步骤:骨架中的某些步骤(通常是步骤A、B或C的具体逻辑)被定义为 抽象方法 或 可重写的方法,由子类来实现。
答案是肯定的:它定义算法骨架,并允许子类在不改变骨架结构的情况下,重新定义骨架中的某些特定步骤。
PHP 示例演示
假设我们要制作一个通用的“数据导出”流程,骨架是固定的:连接数据库 -> 2. 查询数据 -> 3. 格式化数据 -> 4. 输出文件,但连接不同数据库(MySQL vs. PostgreSQL)的方式不同。
<?php
// 1. 抽象类:定义算法骨架
abstract class DataExporter
{
/**
* 模板方法(定义骨架)
* final 关键字防止子类重写整个流程
*/
final public function export(string $filePath): void
{
$connection = $this->connectDatabase(); // 步骤1:连接(子类实现)
$rawData = $this->queryData($connection); // 步骤2:查询(子类实现)
$formattedData = $this->formatData($rawData); // 步骤3:格式化(通用实现,但子类也可覆盖)
$this->outputToFile($formattedData, $filePath); // 步骤4:输出(通用实现)
$this->cleanup($connection); // 钩子方法(可选)
}
// 抽象方法:必须由子类实现
abstract protected function connectDatabase(): object;
abstract protected function queryData(object $connection): array;
// 具体方法:通用实现,子类可以选择覆盖
protected function formatData(array $data): string
{
return json_encode($data); // 默认使用 JSON 格式
}
// 具体方法:通用实现(通常不覆盖)
protected function outputToFile(string $data, string $path): void
{
file_put_contents($path, $data);
echo "文件已导出至: {$path}\n";
}
// 钩子方法:空实现,子类可选覆盖
protected function cleanup(object $connection): void
{
// 默认不做清理
}
}
// 2. 具体子类:实现特定步骤
class MySQLExporter extends DataExporter
{
protected function connectDatabase(): object
{
echo "连接 MySQL 数据库...\n";
return new stdClass(); // 模拟连接对象
}
protected function queryData(object $connection): array
{
echo "使用 MySQL 语法查询数据...\n";
return [['id' => 1, 'name' => 'Alice']];
}
// 覆盖格式化方法
protected function formatData(array $data): string
{
return "MySQL格式: " . implode(', ', array_keys($data[0]));
}
}
class PostgreSQLExporter extends DataExporter
{
protected function connectDatabase(): object
{
echo "连接 PostgreSQL 数据库...\n";
return new stdClass();
}
protected function queryData(object $connection): array
{
echo "使用 PostgreSQL 语法查询数据...\n";
return [['id' => 1, 'name' => 'Bob']];
}
// 使用默认的 JSON 格式化,不覆盖
}
// 3. 客户端使用
function exportAndShow(DataExporter $exporter, string $file): void
{
// 调用模板方法,执行固定的骨架
$exporter->export($file);
}
echo "=== 使用 MySQL 导出 ===\n";
exportAndShow(new MySQLExporter(), '/tmp/mysql_data.txt');
echo "\n=== 使用 PostgreSQL 导出 ===\n";
exportAndShow(new PostgreSQLExporter(), '/tmp/pg_data.txt');
?>
输出效果:
=== 使用 MySQL 导出 ===
连接 MySQL 数据库...
使用 MySQL 语法查询数据...
MySQL格式: id, name
文件已导出至: /tmp/mysql_data.txt
=== 使用 PostgreSQL 导出 ===
连接 PostgreSQL 数据库...
使用 PostgreSQL 语法查询数据...
文件已导出至: /tmp/pg_data.txt
关键点观察:
export()方法(骨架)在父类中定义,且使用final保护,子类无法改变执行顺序(连接 -> 查询 -> 格式化 -> 输出)。connectDatabase()和queryData()是抽象的,子类必须提供不同的实现。formatData()是可选的“钩子”,子类可以覆盖(如 MySQL 覆盖了),也可以不覆盖(如 PostgreSQL 使用默认 JSON)。
模板方法模式的核心特征
| 特征 | 说明 |
|---|---|
| 意图 | 定义一个操作的算法骨架,并将一些步骤延迟到子类中实现。 |
| 关键结构 | 抽象父类:包含 final 的模板方法(骨架)和若干个抽象/具体方法。具体子类:实现父类定义的抽象方法(步骤细节)。 |
| 与策略模式区别 | 模板方法是 继承 层面的复用(固定骨架,子类填空);策略模式是 组合 层面的复用(替换整个算法)。 |
| 适用场景 | 多个类有相同的处理流程,但其中某些步骤的具体逻辑不同(如框架中的初始化、ORM 的保存流程、支付网关的调用流程)。 |
| 优点 | 代码复用(骨架在父类只写一次)。 扩展性好(新增子类只需实现少数方法)。 符合开闭原则(对扩展开放,对修改关闭)。 |
当你需要 固定业务流程 但允许 灵活定制具体步骤 时,模板方法模式就是最佳选择。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播