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

来源:互联网 发布:mac打开远程桌面 编辑:程序博客网 时间:2024/05/16 05:36

装饰模式

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

装饰模式使用组合和委托而不是只使用继承来解决功能变化的问题。实际上,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
原创粉丝点击