• 作者:老汪软件技巧
  • 发表时间:2024-08-25 10:06
  • 浏览量:

在前面几篇中,我们已经了解了结构型模式中的适配器模式、桥接模式和组合模式。本篇我们要介绍的装饰模式看上去和适配器模式、桥接模式很相似,都是使用组合方式来扩展原有类的,但其实本质上却相差甚远呢。

简单来说,适配器模式侧重于转换,而装饰模式侧重于动态扩展;桥接模式侧重于横向宽度的扩展,而装饰模式侧重于纵向深度的扩展。那么装饰模式到底有哪些需要我们重点学习的地方呢?下面,我们一起来看看吧

一、模式原理分析

装饰模式的原始定义是:允许动态地向一个现有的对象添加新的功能,同时又不改变其结构,相当于对现有的对象进行了一个包装。

这个定义非常清晰易懂,因为不能直接修改原有对象的功能,只能在外层进行功能的添加,所以装饰模式又叫包装器模式。

下面我们还是直接来看看装饰模式的 UML 图:

从 UML 图中,我们能发现装饰模式的四个关键角色。

接下来我们再来看看它的代码实现:

//组件
public interface Component {
    void excute();
} 
//具体组件
public class BaseComponent implements Component {
    @Override
    public void excute() {
        //do something
    }
}
//装饰器
public class BaseDecorator implements Component {
    private Component wrapper;
    public BaseDecorator(Component wrapper) {
        this.wrapper = wrapper;
    }
    @Override
    public void excute() {
        wrapper.excute();
    }
}
//具体装饰器A
public class DecoratorA extends  BaseDecorator {
    public DecoratorA(Component wrapper) {
        super(wrapper);
    }
    @Override
    public void excute() {
        super.excute();
    }
}
//具体装饰器B
public class DecoratorB extends  BaseDecorator {
    public DecoratorB(Component wrapper) {
        super(wrapper);
    }
    @Override
    public void excute() {
        super.excute();
    }
}

这段代码实现比较简单,组件 Component 定义了组件具备的基本功能,具体组件 BaseComponent 是对组件(接口)的一种基础功能的实现,装饰器 BaseDecorator 中包含 Component 的抽象实例对象,作为装饰器装饰的目标对象,具体装饰器 DecoratorA 和 DecoratorB 继承装饰器 BaseDecorator 来进行具体附加功能的沿用与扩展。

所以说,装饰模式本质上就是给已有不可修改的类附加新的功能,同时还能很方便地撤销。

二、使用场景分析

一般来讲,装饰模式常用的使用场景有以下几种。

在现实中有一个很形象的关于装饰器使用场景的例子,那就是单反相机镜头前的滤镜。用过单反相机的同学应该知道,不加滤镜其实不会影响拍照,而滤镜实际上就是一个装饰器,滤镜上又可以加滤镜,这样就做到了不改变镜头而又给镜头增加了附加功能。

三、为什么要使用装饰器模式

分析完装饰模式的原理和使用场景后,我们再来说说使用装饰模式的原因,主要有以下两个。

第一个,为了快速动态扩展类功能,降低开发的时间成本。 比如,一个类 A,有子类 A01、A02,然后 A01 又有子类 A001,以此类推,A0001、A00001……这样的设计会带来一个严重的问题,那就是:当需要扩展 A01 时,所有 A01 的子类和父类都会受到影响。但是,如果这时我们使用装饰器 B01、B02、C01、C02,那么扩展 A01 就会变为 A01B01C01、A01B02C02 这样的组合。这样就能快速地扩展类功能,同时还可以按需来任意组合,极大地节省了开发时间。

第二个,希望通过继承的方式扩展老旧功能。 比如,前面我们说到,当类标识有 final 关键字时,要想复用这个类就只能通过重新复制代码的方式,不过通常这样的类又处于需要对外提供功能的状态,不能轻易修改,而梳理上下文逻辑又费时费力,那么采用装饰模式就是一个很好的选择。因为装饰器是在外层进行扩展,即使功能不合适,也能及时地撤销而不影响原有的功能。所以说,在一些维护系统的升级或重构场景中,使用装饰模式来重构代码,在短期内都能达到快速解耦的效果。

四、装饰器模式的优缺点是什么?

使用装饰模式主要有以下四个大的优点。

同样,装饰模式也有一些缺点。

装饰模式就像是我们送人礼物时的“包装盒”,我们可以选择各种各样的包装盒,还可以在包装盒里嵌套包装盒。

装饰模式在结构上体现为链式结构,通过在外层不断地添加具体装饰器类来对原有的组件类进行扩展,这样在保证原有功能的情况下,还能额外附加新的功能。这也是学习和理解装饰模式的核心所在。