php设计模式(二十二):模版方法模式(Template Method)
- 陈大剩
- 2023-06-12 10:11:42
- 1931
模版方法模式
模版方法模式又称为:Template Method。模板方法是一种行为设计模式,它在超类中定义了一个 算法(抽象方法) 的框架,允许子类在不修改结构的情况下重写 算法(抽象方法) 的特定步骤。
模板方法(Template Method)是一个比较简单的模式。它的主要思想是,定义一个操作的一系列步骤,对于某些暂时确定不下来的步骤,就留给子类去实现好了,这样不同的子类就可以定义出不同的步骤。
可能你已经见过这种模式很多次了,只是看不出来他是一种设计模式而已。它是一种让抽象模板的子类“完成”一系列算法的行为策略。它是一种非常适合框架库的算法骨架(抽象方法)。用户只需要实现子类的一种方法,其父类便可去完成这项工作。
问题
假设我们负责制作不同品牌 内存条,各种种品牌的内存条都包含:品牌、内存大小、内存颗粒类型、运行参数等。运行参数信息每种品牌都需要有且需要统一规范(CPU 才能读取信息),这样我们为每个品牌单独写了 品牌独立的类。
一段时间后,我们发现这些各种 品牌独立的类 中包含 许多相似代码。尽管这些类品牌、内存大小、内存颗粒可能完全不同,但 获取参数 和 运行 的代码却几乎完全一样。如果能在保持算法结构完整的情况下去除重复代码,这难道不是一件很棒的事情吗?
解决方法
我们将复杂的运行算法分解为一系列步骤,然后将这些步骤 改写为方法,最后在 “模板方法” 中依次调用这些方法。步骤可以是 抽象的,也可以有一些默认的实现。
对于完全相同的代码使用继承 抽象类 超类中的方法,不同的方法我们申请抽象方法,然后强制要求子类自行实现这些方法。
结构
Memory: 内存抽象类,定义操作中骨架;比如说执行顺序等;讲具体的执行内容延迟到子类;
Samsung、SanDisk、Kingston:具体品牌内存子类,定义具体的执行内容;
代码示例
内存抽象类
/**
* 内存抽象类
*/
abstract class Memory
{
/**
* 品牌
* @return string
* @author chendashe\ngpc
*/
abstract public function brand(): string;
/**
* 内存大小
* @return string
* @author chendashengpc
*/
abstract public function size(): string;
/**
* 运行参数
* @return void
* @author chendashengpc
*/
public function config()
{
echo '内存品牌:' . $this->brand() . PHP_EOL;
echo '内存大小:' . $this->size() . PHP_EOL;
echo '内存颗粒:' . $this->particles() . PHP_EOL;
}
/**
* 运行方法,运行是通用的。
* @return void
* @author chendashengpc
*/
public function run()
{
echo '开始运行 ' . $this->brand() . ' 内存条' . PHP_EOL;
$this->config();
// do something
}
/**
* 内存颗粒
* @return void
* @author chendashengpc
*/
public function particles(): string
{
return 'TLC';
}
}
具体子类
/**
* 金士顿
*/
class Kingston extends Memory
{
public function brand(): string
{
return '金士顿(Kingston)';
}
public function size(): string
{
return '8 Gb';
}
public function particles(): string
{
return 'MLC';
}
}
/**
* 三星
*/
class Samsung extends Memory
{
public function brand():string
{
return '三星(Samsung)';
}
public function size():string
{
return '16 Gb';
}
}
/**
* 闪迪
*/
class SanDisk extends Memory
{
public function brand(): string
{
return '闪迪(SanDisk)';
}
public function size(): string
{
return '8 Gb';
}
}
客户端使用
/**
* 金士顿
*/
$kingston = new Kingston();
$kingston->run();
echo PHP_EOL;
/**
* 三星
*/
$samsung = new Samsung();
$samsung->run();
echo PHP_EOL;
/**
* 闪迪
*/
$sandisk = new SanDisk();
$sandisk->run();
echo PHP_EOL;
输出
内存品牌:金士顿(Kingston)
内存大小:8 Gb
内存颗粒:MLC
内存品牌:三星(Samsung)
内存大小:16 Gb
内存颗粒:TLC
内存品牌:闪迪(SanDisk)
内存大小:8 Gb
内存颗粒:TLC
UML
优缺点
优点
- 可仅允许客户端重写一个大型算法中的特定部分,使得算法其他部分修改对其所造成的影响减小。
- 可将重复代码提取到一个超类中。
缺点
- 部分客户端可能会受到算法框架的限制。
- 通过子类抑制默认步骤实现可能会导致违反 里氏替换原则。
- 模板方法中的步骤越多, 其维护工作就可能会越困难。