php装饰器模式理解与实际场景

本文通过对比传统的继承方式与装饰器模式,展示了如何利用装饰器模式动态地为对象添加功能,避免了代码冗余和过度继承。通过一个PHP示例,解释了装饰器模式在请求处理中的应用,以及如何实现类似中间件的功能。这种模式在需要灵活组合功能的场景下具有很好的扩展性,并以Laravel框架的实现作为参考。
摘要由CSDN通过智能技术生成

- 作用
不改变原对象,动态的给一个对象添加/修改功能。
为什么不直接用继承?
下面代码我们实际上是要给RequestHand2 hand增加新的功能。

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2021/9/28
 * Time: 23:13
 */

//请求类
class Request
{

}

//抽象类  请求处理类
abstract class RequestHand
{
    //处理请求
    abstract function hand(Request $request);

}


//正常请求处理
class RequestHand2 extends RequestHand
{
    function hand(Request $request)
    {
        echo "正常处理\n";
    }
}

//加一个验证请求
class Auth extends RequestHand2
{
    function hand(Request $request)
    {
        echo "验证请求\n";
        parent::hand($request);
    }
}

//加一个记录日志功能
class Log extends RequestHand2
{
    function hand(Request $request)
    {
        parent::hand($request);
        echo "记录日志\n";
    }
}


//请求
$request = new Request();
//正常处理就可以这么写
(new RequestHand2())->hand($request);

//我对请求过滤 我要验证请求
(new Auth())->hand($request);

// 我要记录日志
(new Log())->hand($request);

上述代码就会出现这样一个问题,如何我又要验证请求又要记录日志怎么办,那么我只能再加一个类。

class AuthAndLog extends RequestHand2
{
    function hand(Request $request)
    {
        echo "验证请求\n";
        parent::hand($request);
        echo "记录日志\n";
    }
}

或者

class AuthAndLog extends Log
{
    function hand(Request $request)
    {
        echo "验证请求\n";
        parent::hand($request);
    }
}

很明显,这样处理会出现重复代码或者造成许多层继承的问题,这还是只有两个功能,如果有若干个,代码冗余直接爆炸。

  • 装饰器模式实现
<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2021/9/28
 * Time: 23:13
 */

//请求类
class Request
{

}

//抽象类  请求处理类
abstract class RequestHand
{
    //处理请求
    abstract function hand(Request $request);

}


//正常请求处理
class RequestHand2 extends RequestHand
{
    function hand(Request $request)
    {
        echo "正常处理\n";
    }
}

//装饰抽象类
abstract class RequestHandDecorate extends RequestHand{
    protected $requestHand;

    public function __construct(RequestHand $rh)//注入RequestHand类 这是重点
    {
       $this->requestHand=$rh;
    }
}


//加一个验证请求
class Auth extends RequestHandDecorate
{
    function hand(Request $request)
    {
        echo "验证请求\n";
        $this->requestHand->hand($request);
    }
}

//加一个记录日志功能
class Log extends RequestHandDecorate
{
    function hand(Request $request)
    {
        $this->requestHand->hand($request);
        echo "记录日志\n";
    }
}



//请求
$request = new Request();
//正常处理就可以这么写
(new RequestHand2())->hand($request);

echo "---------\n";

//我对请求过滤 我要验证请求
(new Auth(new RequestHand2()))->hand($request);

echo "---------\n";

// 我要记录日志
(new Log(new RequestHand2()))->hand($request);

echo "---------\n";

//我又要记录又要验证
(new Auth(new Log(new RequestHand2())))->hand($request);


结果
在这里插入图片描述

这样的模型极具扩展性,可以非常轻松的添加新的装饰器并且随意的组合!

  • 实际应用场景
  • 上述代码实际上就实现了一个简单的中间件,但是这样写的话,如果有多个处理,会写许多嵌套。可以参考laravel的实现。laravel装饰类不是从构造函数注入实例,而是从方法传入闭包,再使用arrary_reduce来包装中间件,最后统一调用,这样就不用写多重嵌套了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值