zoukankan      html  css  js  c++  java
  • 【PHP设计模式】结构型之装饰者(Decorator)

    装饰者模式(Decorator)

    意图:

      【GoF】动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活

    <动机>

      组合模式帮助我们聚合组件,而装饰模式则使用类似结构来帮助我们改变具体组件的功能。该模式同样使用组合,但组合是在代码运行时实现的。继承是共享父类特性的一种简单的办法,但可能会使你将需要改变的特性硬编码到继承体系中,这会降低系统的灵活性。

      将所有功能建立在集成体系上会导致系统中的类爆炸式增多,同时尝试对继承树上的不同分支做相似的修改时,代码可能产生重复。

    <适用>

      一、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

      二、处理那些可以撤销的职责。

      三、当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸式增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成类。

    <Decorator优点>

      比静态继承更灵活。

      避免在层次结构高层的类有太多的特征。

    <Decorator缺点>

      Decorator与Component不一样。Decorator是一个透明的包装。包装后的组件与原来的组件是有区别的,不能依赖对象标志了。

      有许多的小对象。

    <UML>

      抽象构件角色(Component):定义一个抽象接口,来规范准备附加功能的类。

          具体构件角色(ConcreteComponent):将要被附加功能的类,实现抽象构件角色接口。

          抽象装饰者角色(Decorator):持有对具体构件角色的引用并定义与抽象构件角色一致的接口。

          具体装饰角色(ConcreteDecorator):实现抽象装饰者角色,负责为具体构件添加额外功能。

    <执行方式>

      Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作。该模式以对客户端透明的方式扩展对象的功能。

    <示例一>在游戏中,假设你占据了一定的地盘Tile ,那么这个地盘可以给你提供财富资源getWealthFactor,如果地盘上有钻石,那么能够提供更多的财富资源,如果被污染了就要减少资源了。

    abstract class Tile {
        abstract function getWealthFactor();
    }
    
    class Plains extends Tile {
        private $wealthfactor = 2;
        function getWealthFactor() {
            return $this->wealthfactor;
        }
    }
    
    class DiamondPlains extends Plains {
        function getWealthFactor() {
            return parent::getWealthFactor() + 2;
        }
    }
    
    class PollutedPlains extends Plains {
        function getWealthFactor() {
            return parent::getWealthFactor() - 4;
        }
    }
    
    $tile = new PollutedPlains();
    print $tile->getWealthFactor();

    <Result>

    -2

    随着需要的种类的增多,将会导致产生越来越多的类,比如说有钻石同时又被污染的类,我们就需要新建一个新类。如何才能不这样做呢,这就需要用到装饰者模式了:

    abstract class Tile {
        abstract function getWealthFactor();
    }
    
    class Plains extends Tile {//平原
        private $wealthfactor = 2;
        function getWealthFactor() {
            return $this->wealthfactor;
        }
    }
    
    abstract class TileDecorator extends Tile {//继承了abstract function getWealthFactor
        protected $tile;
        function __construct( Tile $tile ) {//引用Tile
            $this->tile = $tile;    
        }
    }
    
    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 = new PollutionDecorator( new DiamondDecorator( new Plains() ))就实现了钻石平原遭受污染的问题。

    <示例二>

    处理不同请求
    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
    ";
        }
    }
    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
    "."<br>";
            $this->processrequest->process( $req );
        }
    }
    //验证请求
    class AuthenticateRequest extends DecorateProcess {
        function process( RequestHelper $req ) {
            print __CLASS__.": authenticating request
    "."<br>";
            $this->processrequest->process( $req );
        }
    }
    //结构请求
    class StructureRequest extends DecorateProcess {
        function process( RequestHelper $req ) {
            print __CLASS__.": structuring request data
    ";
            $this->processrequest->process( $req );
        }
    }
    $process = new AuthenticateRequest( new StructureRequest(new LogRequest (new MainProcess())));
    $process->process( new RequestHelper() );

    <Result>

    AuthenticateRequest: authenticating request 
    StructureRequest: structuring request data LogRequest: logging request 
    MainProcess: doing something useful with request 

    <示例三>卖冰激凌

      现在要给冰激凌有牛奶和沙冰的,现在又要给牛奶和沙冰的冰激凌加入香草,草莓等味道,这个时候我们可以先要一个牛奶冰激凌,然后选择加入的配料,在选择过程中加入配料的价格与描述。用这个装饰功能的配料在需要的时候装饰冰激凌!

    抽象构件角色>>冰激凌抽象类:描述与价格

    abstract class ICE{
      public abstract function getDescription();
      public abstract function cost();
    }

    具体构件角色>>牛奶冰激凌

    class MilkIce extends ICE {
      public $description = '纯牛奶制作的冰激凌';
      public function getDescription(){
        $this->description = $description;
      }
      public function cost(){
        return 17;
      }
    }

    具体构件角色>>沙冰冰激凌:

    class SlushIce extends ICE {
      public $description = '沙冰制作的冰激凌';
      public function getDescription(){
        $this->description = $description;
      }
      public function cost(){
        return 10;
      }
    }

    抽象装饰者角色>>现在需要实现的是给沙冰或牛奶冰激凌加入调料!建立调料的抽象类

    abstract class CondimentIce extends ICE{
      //内部继承了父类的抽象方法
    }

    具体装饰角色>>加入香草的调料

    class Herb extends CondimentIce
    {
        public $ice;
        public $description;
    
        public function __construct($ice)
        {
            $this->ice = $ice;
            $this->description = '法国香草';
        }
    
        public function getDescription()
        {
            return $this->ice->getDescription() . ',' . $this->description;
        }
    
        public function cost()
        {
            return $this->ice->cost() + 5;
        }
    }

    具体装饰角色>>加入草莓调料

    class Berries extends CondimentIce
    {
        public $ice;
        public $description;
    
        public function __construct($ice)//这里传入的是冰激凌对象,对这个对象执行操作
        {
            $this->ice = $ice;
            $this->description = '野草莓';
        }
    
        public function getDescription()
        {
            return $this->ice->getDescription() . ',' . $this->description;
        }
    
        public function cost()
        {
            return $this->ice->cost() + 8;
        }
    }

    调用示例:

    // 购买一个奶油香草冰激凌
    $ice_object = new MilkIce();
    $ice_object = new Herb($ice_object);//加入香草
    echo $ice_object->cost();
    echo $ice_object->getDescription();
    
    // 购买一个沙冰+香草+草莓
    $ice2 = new SlushIce();
    $ice2 = new Herb($ice2);//加入香草
    $ice2 = new Berries($ice2);//加入草莓
    echo $ice2->cost();
    echo $ice2->getDescription();
  • 相关阅读:
    jdk和dubbo的SPI机制
    何谓架构
    ElasticSearch的API使用
    LFU的基本原理与实现
    如何判断单向链表有环?
    mysql执行过程以及顺序
    原来 TinyPNG 可以这样玩!
    deno + mongodb 实战踩坑记
    好消息,vue3.0 进入 beta 阶段!
    听说会做这道题的人后来都进了头条?
  • 原文地址:https://www.cnblogs.com/colorstory/p/2663084.html
Copyright © 2011-2022 走看看