深入PHP面向对象、模式与实践——让面向对象编程更加灵活的模式(2)

装饰模式

组合模式帮助我们聚合组件,而装饰模式则使用类似结构来帮助我们改变具体组件的功能。

装饰模式使用组合和委托而不是只使用继承来解决功能变化的问题。实际上,Decorator类会持有另外一个类的实例。Decorator对象会实现与被调用对象的方法相对应的类方法。用这种办法可以在运行时创建一系列的Decorator对象。

abstract class Tile
{
    abstract function getWealthFactor();
}

class Plains extends Tile
{
    private $wealthfactor = 2;

    function getWealthFactor()
    {
        return $this->wealthfactor;
    }
}

abstract class TileDecorator extends Tile
{
    protected $tile;

    function __construct(Tile $tile)
    {
        $this->tile = $this;
    }
}

class DiamondDecorator extends TileDecorator
{
    function getWealthFactor()
    {
        return $this->tile->getWealthFactor() + 2;
    }
}

class PollutionDecorator extends TileDecorator
{
    function getWealthFactor()
    {
        return $this->tile->getWealthFactor() - 4;
    }
}

$tile = new Plains();
print $tile->getWealthFactor();//2

$tile = new DiamondDecorator(new Plains());
print $tile->getWealthFactor();//4

$tile = new PollutionDecorator(new DiamondDecorator(new Plains()));
print $tile->getWealthFactor();//0

通过像这样使用组合和委托,可以在运行时轻松地合并对象。因为模式中所有对象都扩展自Tile,所以客户端代码并不需要知道内部是如何合并的。

本例的类图如下:
这里写图片描述
这样的模型极具扩展性。我们可以非常轻松地添加新的装饰器或新的组件。通过使用大量装饰器,我们可以在运行时创建极为灵活的结构。

装饰模式建立的管道对于创建过滤器非常有用。客户端程序员可将核心组件与装饰对象合并,从而对核心方法进行过滤、缓冲、压缩等操作。下面是一个使用装饰模式的web请求实例:

class RequestHelper
{
}

abstract class ProcessRequest
{
    abstract function process(RequestHelper $req);
}

class MainProcess extends ProcessRequest
{
    function process(RequestHelper $req)
    {
        print __CLASS__ . ":doing something useful with request\n";
    }
}

abstract class DecorateProcess extends ProcessRequest
{
    protected $processrequest;

    function __construct(ProcessRequest $pr)
    {
        $this->processrequest = $pr;
    }
}

class LogRequest extends DecorateProcess
{
    function process(RequestHelper $req)
    {
        print __CLASS__ . ":logging request\n";
        $this->processrequest->process($req);
    }
}

class AuthenticateRequest extends DecorateProcess
{
    function process(RequestHelper $req)
    {
        print __CLASS__ . ":authenticating request\n";
        $this->processrequest->process($req);
    }
}

class StructureRequest extends DecorateProcess
{
    function process(RequestHelper $req)
    {
        print __CLASS__ . ":structuring request\n";
        $this->processrequest->process($req);
    }
}

$process = new AuthenticateRequest(new StructureRequest(new LogRequest(new MainProcess())));
$process->process(new RequestHelper());

一定要记住:组合和继承通常都是同时使用的。因为装饰对象作为子对象的包装,所以保持基类中的方法尽可能少是很重要的。如果一个基类具有大量的特性,那么装饰对象不得不为它们包装的对象的所有public方法加上委托。你可以用一个抽象的装饰类来实现,不过这仍旧会带来耦合,并可能导致bug的出现。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值