PHP设计模式-装饰者模式
学习背景:
- 学习 laravel 框架时,发现中间件功能可以即插即用,随意扩展。但又因为其过于灵活,加之没搞明白实现原理,以致于几次工作中碰壁。为搞懂其原理,在揭开其神奇的面纱时,学习到 laravel 的中间件功能是通过装饰者模式来实现的,于是就误打误撞学习了一个新的设计模式,即
装饰者模式
。
模式介绍:
- 装饰者模式是在
开放—关闭
原则下实现动态添加或减少功能的一种方式 - 装饰类和被装饰类可以独立发展,不会相互耦合
- 装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能,以及动态撤销
代码示例:中间件原理
<?php
interface Middleware
{
public static function handle(Closure $next);
}
class A implements Middleware
{
public static function handle(Closure $next)
{
echo "A start part" . PHP_EOL;
$next();
echo "A end part" . PHP_EOL;
}
}
class B implements Middleware
{
public static function handle(Closure $next)
{
echo "B start part" . PHP_EOL;
$next();
echo "B start part" . PHP_EOL;
}
}
function getSlice()
{
return function ($stack, $pipe) {
return function () use ($stack, $pipe) {
return $pipe::handle($stack);
};
};
}
function then()
{
$pipes = ["A", "B"];
$firstSlice = function () {
echo "respond data" . PHP_EOL;
};
$pipes = array_reverse($pipes);
call_user_func(array_reduce($pipes, getSlice(), $firstSlice));
}
then();
- 示例代码中的
call_user_func(array_reduce($pipes, getSlice(), $firstSlice));
可能比较难理解。搞懂他们,我们还需要知道,call_user_func
的作用是把第一个参数作为回调函数调用;array_reduce ( array $array , callable $callback , mixed $initial = null )
的作用是将回调函数 callback 迭代地作用到 array 数组中的每一个单元中,从而将数组简化为单一的值。 - 假设参数不变的情况下,上面代码可以解析成:
call_user_func(function () {
return A::handle(
function () {
return B::handle(
function () {
echo "respond data" . PHP_EOL;
}
);
}
);
});
- 如果上面那段还不容易理解,你还可以把它看成:
call_user_func(function () {
echo "A start part" . PHP_EOL;
call_user_func(function () {
echo "B start part" . PHP_EOL;
call_user_func(function () {
echo "respond data" . PHP_EOL;
});
echo "B start part" . PHP_EOL;
});
echo "A end part" . PHP_EOL;
});
扩展知识:
- 在实际框架中的大致原理即使如此。示例中的
firstSlice
闭包,在实际中的作用是将request
对象分发给路由服务提供者来处理并获取到响应的结果 - 看完上面示例,也就搞懂了,什么在中间件里面,即可以获取到请求的参数,也可以拿到响应的值
- 看完示例,也就搞懂了,为什么参考资料都说 中间件 的实现模式像个洋葱了