装饰者模式

一、需求

现在有这样一个需求,公司要开发一个图片应用,首先图片上传到服务器,保存原图。然后再将图片裁剪,加水印,再存一份新的处理后的图。

针对这样一个需求,我们该如何做呢?

很容易想到,我们写一个图片处理类:里面封装几个方法:上传、裁剪、加水印。

但是这样做有什么不好的地方呢?首先,我们现在的需求是只有这几个处理,后续可能会根据业务需要不断增加新的处理,比如说加滤镜、加背景图等等,这样我们就需要不断在我们原来的类的基础上加新的方法,而且我们原来的方法有可能有需要优化的地方,那么这个图片处理的基类就会不断的进行修改,万一我们想多人协作每个人写一个方法呢,又万一我在新增方法的时候不小心将原来的方法给加减了什么呢?这真是很糟糕的做法。

那么,如何做更好一些呢?没错,装饰者模式能很好的解决我们这个问题。

二、什么是装饰者模式

装饰者模式,就是可以动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。

三、实现代码

//图片处理接口类
interface ImgProccessor
{
    public function showResult();
}

//图片处理实体类
class ImgComponent implements ImgProccessor
{
    private $url;
    public function __construct($url)
    {
        $this->url = $url;
    }

    public function showResult()
    {
        echo '图片的原路径为:',$this->url,PHP_EOL;
    }
}

//图片处理装饰者抽象类
abstract class ImgDecorator implements ImgProccessor
{
    protected $imgProccessor;
    public function __construct(ImgProccessor $imgProccessor)
    {
        $this->imgProccessor = $imgProccessor;
    }

    public abstract function showResult();
}

//图片处理(裁切类)
class Crop extends ImgDecorator
{
    public function __construct(ImgProccessor $imgProccessor)
    {
        parent::__construct($imgProccessor);
    }

    private function cropImg()
    {
        echo ',图片经过了裁切处理',PHP_EOL;
    }

    public function showResult()
    {
        $this->imgProccessor->showResult();
        $this->cropImg();
    }
}

//图片处理(加水印类)
class WaterMark extends ImgDecorator
{
    public function __construct(ImgProccessor $imgProccessor)
    {
        parent::__construct($imgProccessor);
    }

    public function waterMarkImg()
    {
        echo ',图片加过了加水印处理',PHP_EOL;
    }

    public function showResult()
    {
        $this->imgProccessor->showResult();
        $this->waterMarkImg();
    }
}

四、优势劣势

    优点:

           1、装饰者模式可以提供比继承更多的灵活性

           2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。

           3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。

           4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

    缺点:

           1、会产生很多的小对象,增加了系统的复杂性

           2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

五、适用场景

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

    2、需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。  当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

六、UML图

原文地址:https://www.cnblogs.com/gspsuccess/p/9235348.html