装饰器模式和适配器模式

装饰器模式

装饰器模式(Decorator )允许向一个现有的对象添加新的增强功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装

一般的,我们为了扩展一个类经常使用继承方式实现,但随着扩展功能的增多,子类会很膨胀。在不想增加很多子类的情况下扩展类。这个时候就可以通过装饰器模式动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。但缺点就是多层装饰比较复杂。

那它是怎么实现的呢?
通过先将具体功能职责划分好,对于每部分功能职责,都有一个实现了原始类接口的装饰器类,装饰器类可以有继承它的子类来添加额外的职责。装饰模式是直接继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

举例实现:

我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。

RedShapeDecorator 是实现了 ShapeDecorator 的实体类。DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。

装饰器模式和适配器模式_第1张图片具体代码实现步骤:菜鸟教程:装饰器模式

装饰器模式最经典的应用:Java IO 类

Java IO 类库非常庞大和复杂,负责 IO 数据的读取和写入。如果对 Java IO类做一下分类,我们可以从下面两个维度将它划分为四类。具体如下所示:
装饰器模式和适配器模式_第2张图片
针对不同的读取和写入场景,Java IO 又在这四个父类基础之上,扩展出了很多子类。
装饰器模式和适配器模式_第3张图片
由于IO库中需要很多性能的各种组合,如果用继承方法实现,那么每一种组合都需要一个类,这样会造成大量性能重复的类出现。如果使用装饰器模式,那么类的数目大大减少,性能的重复也减到最少。因此装饰器模式是IO中的基本模式。

适配器模式

适配器模式(Adapter)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

怎么实现的呢?
这是通过继承和依赖关系(这里具体指组合)实现的,适配器继承或依赖已有的对象,实现想要的目标接口。

举例实现:
有一个 MediaPlayer 接口和一个实现了 MediaPlayer 接口的实体类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。
我们还有另一个接口 AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 vlc 和 mp4 格式的文件。
我们想要让 AudioPlayer 播放其他格式的音频文件。为了实现这个功能,我们需要创建一个实现了 MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。
AudioPlayer 使用适配器类 MediaAdapter 传递所需的音频类型,不需要知道能播放所需格式音频的实际类。AdapterPatternDemo 类使用 AudioPlayer 类来播放各种格式。

装饰器模式和适配器模式_第4张图片
具体代码实现步骤:菜鸟教程:适配器模式

适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。上面案例中的适配器类就是个使用组合关系实现的对象适配器。MediaAdapter类和AdvancedMediaPlayer 类是组合关系,如果是继承关系,那就是类适配器了。

适配器模式应用场景有

  1. 封装有缺陷的接口设计;
  2. 统一多个类的接口设计;
    某个功能的实现依赖多个外部系统(或者说类)
  3. 替换依赖的外部系统;
    当我们把项目中依赖的一个外部系统替换为另一个外部系统的时候,利用适配器模式,可以
    减少对代码的改动。
  4. 兼容老版本接口;
  5. 适配不同格式的数据;

适配器模式比较常见的应用: Java 日志

Java 中有很多日志框架,在项目开发中,我们常常用它们来打印日志信息。其中,比较常用的有 log4j、logback,以及 JDK 提供的 JUL(java.util.logging) 和 Apache 的JCL(Jakarta Commons Logging) 等。

大部分日志框架都提供了相似的功能,但它们却并没有实现统一的接口。
如果我们开发的是一个集成到其他系统的组件、框架、类库等,那日志框架的选择就没那么随意了。如果引入多个组件,每个组件使用的日志框架都不一样,那日志本身的管理工作就变得非常复杂。所以,为了解决这个问题,我们需要统一日志打印框架。

对于java开发者, Slf4j 这个日志框架你肯定不陌生,它相当于 JDBC 规范,提供了一套打印日志的统一接口规范。不过,它只定义了接口,并没有提供具体的实现,需要配合其他日志框架(log4j、logback……)来使用。而且它不仅仅提供了统一的接口定义,还提供了针对不同日志框架的适配器。对不同日志框架的接口进行二次封装,适配成统一的 Slf4j 接口定义。
并且Slf4j 不仅仅提供了从其他日志框架到 Slf4j 的适配器,还提供了反向适配器,也就是从 Slf4j 到其他日志框架的适配。

代理、装饰器、适配器 这3 种设计模式的特点和区别

代理模式:代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。

装饰器模式:装饰者模式在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器的嵌套使用。

适配器模式:适配器模式是一种事后的补救策略。适配器提供跟原始类不同的接口,而代理模式、装饰器模式提供的都是跟原始类相同的接口。

你可能感兴趣的:(设计模式,装饰器模式,适配器模式)