代码编程之策略模式-php专题
2026年2月2日大约 4 分钟
代码编程之策略模式-php专题
何时使用策略模式
在实际工作中,可能会出现大量的switch和if判断,这种硬编码的方式不利于后续工作的拓展和维护,这时候最好的方式就是使用策略模式
一复杂业务场景示例
<?php
/**
* 策略模式 完整示例(按你笔记思路实现)
* 场景:电商首页,根据用户性别展示不同商品类目+广告
*/
// 1. 定义策略接口(核心:统一行为规范)
interface UserStrategy
{
public function showCategory(); // 展示商品类目
public function showAd(); // 展示广告
}
// 2. 实现男性策略(继承接口,封装男性行为)
class MaleUserStrategy implements UserStrategy
{
public function showCategory()
{
return "展示:数码、汽车、运动类目";
}
public function showAd()
{
return "展示:数码产品、汽车广告";
}
}
// 3. 实现女性策略(继承接口,封装女性行为)
class FemaleUserStrategy implements UserStrategy
{
public function showCategory()
{
return "展示:美妆、服饰、母婴类目";
}
public function showAd()
{
return "展示:美妆产品、服饰广告";
}
}
// 4. 上下文类(核心:持有策略对象,对外提供统一调用入口)
class UserContext
{
private $strategy; // 策略对象属性
// 注入策略对象(依赖注入,解耦)
public function __construct(UserStrategy $strategy)
{
$this->strategy = $strategy;
}
// 对外统一方法:执行策略行为
public function showPage()
{
$category = $this->strategy->showCategory();
$ad = $this->strategy->showAd();
return "首页展示:{$category} | {$ad}";
}
}
// 5. 客户端调用(根据性别选择策略,无switch/if硬编码)
// 模拟男性用户
$maleContext = new UserContext(new MaleUserStrategy());
echo $maleContext->showPage();
echo PHP_EOL;
// 模拟女性用户
$femaleContext = new UserContext(new FemaleUserStrategy());
echo $femaleContext->showPage();
echo PHP_EOL;
// 扩展:新增儿童策略(只需新增策略类,无需修改原有代码)
class ChildUserStrategy implements UserStrategy
{
public function showCategory()
{
return "展示:玩具、绘本、童装类目";
}
public function showAd()
{
return "展示:玩具、儿童用品广告";
}
}
// 调用儿童策略
$childContext = new UserContext(new ChildUserStrategy());
echo $childContext->showPage();策略模式的优缺点(纯文本,无格式)
优点:
- 符合开闭原则:新增策略只需新增策略类,无需修改原有代码,扩展成本低。
- 代码解耦:将算法 / 行为封装到独立策略类中,与上下文逻辑分离,避免 switch/if 硬编码。
- 可复用性高:策略类可在多个上下文场景中复用,避免重复代码。
- 灵活性强:可动态切换策略(运行时替换策略对象),适配不同业务场景。
- 单一职责:每个策略类只负责一种行为,代码可读性、可维护性更高。
缺点:
- 类数量增多:每个策略对应一个类,策略较多时会导致类文件膨胀。
- 客户端需了解策略:客户端需要知道不同策略的作用,才能选择合适的策略注入。
- 策略间共享逻辑困难:若多个策略有公共逻辑,需额外抽离公共类 /trait,增加设计复杂度。
- 小场景冗余:对于简单、固定的少量分支,策略模式会比直接 switch/if 更繁琐,过度设计。
二简单业务场景示例
提示
用数组做映射,通过绑定闭包函数来执行
<?php
/**
* 数组映射闭包函数 极简示例
* 场景:根据操作类型,执行不同的简单计算
* 无switch/if,纯数组映射,一键扩展
*/
class SimpleCalculate
{
// 定义:操作类型 → 数字标识 + 处理闭包 映射数组
private $operateMap = [
'add' => [
'code' => 10,
'handler' => function ($a, $b) {
return $a + $b;
}
],
'sub' => [
'code' => 20,
'handler' => function ($a, $b) {
return $a - $b;
}
],
'mul' => [
'code' => 30,
'handler' => function ($a, $b) {
return $a * $b;
}
]
];
// 执行计算方法
public function run($operateType, $a, $b)
{
// 校验操作类型是否存在
if (!isset($this->operateMap[$operateType])) {
return '操作类型不存在';
}
$config = $this->operateMap[$operateType];
// 数字标识判断(保证性能)
if ($config['code'] <= 0) {
return '操作标识错误';
}
// 绑定闭包上下文并执行
$handler = $config['handler']->bindTo($this, $this);
return $handler($a, $b);
}
}
// 测试示例
$calc = new SimpleCalculate();
echo $calc->run('add', 2, 3); // 输出:5
echo PHP_EOL;
echo $calc->run('sub', 5, 2); // 输出:3
echo PHP_EOL;
echo $calc->run('mul', 4, 5); // 输出:20
echo PHP_EOL;
echo $calc->run('div', 6, 2); // 输出:操作类型不存在