GOF - 装饰者模式Decorator Pattern 在开源软件中的应用


在这里插入图片描述


定义

装饰模式 Decorator : 在不改变原有功能的基础上, 动态的给一个对象添加一些额外的职责 ,非常符合开闭原则 (对修改关闭,对扩展开放)


结构图

在这里插入图片描述

Component是定义了一个接口(抽象类 、接口都可以),可以给这些对象动态的添加职责。

ConcreteComponent 是定义了一个具体的对象,也可以给这个对象添加一些职责。

Decorator 装饰抽象类, 继承了Component , 从外类来扩展Component类的功能, 但对已Component来讲,是无需知道Decorator的存在的。

至于ConcreteComponent 就是具体的装饰对象,给Component添加职责的功能。


总结下,分工如下:

• Component:抽象构件,装饰者和被装饰者共同的父类,是一个接口或者抽象类,用来定义基本行为
• ConcreteComponent:定义具体对象,即被装饰者
• Decorator:抽象装饰者,继承自Component,从外类来扩展ConcreteComponent
• ConcreteDecorator:具体装饰者,用于扩展ConcreteComponent


需求

【接口 】

package com.gof.decoratorPattern;

public interface Component {

    void operation();

}

【实现类 】

public class ConcreteComponent implements  Component {
    @Override
    public void operation() {
        System.out.println("拍照");
    }
}

要求: 原有的功能不变,已有的代码不允许修改, 但是要支持添加新的功能,功能不确定,可任意组合。

what ? 不让改原来的代码,还得添加新的功能?

不过人家说的也合理啊,开闭原则 (对修改关闭,对扩展开放) ,那再好好琢磨琢磨怎么实现


装饰者模式

怎么办呢? 这正是装饰者模式要解决的问题

如果我们搞个抽象类Decorator , 在Decorator内部持有Component接口,那么Component原来的接口那Decorator肯定也能够重写,既然能重写,重写的时候 添加新功能 是不是能支撑?

当然了 Decorator抽象类 也可以定义一些抽象方法,让子类去重写

走, 试一把

【抽象的装饰类】

/**
 * 抽象类 Decorator
 */
public abstract  class Decorator implements Component {
    // 装饰对象  装饰Component  目的是为了在Component上添加新功能
    Component delegate ;

    // 构造函数  (用set方法也可以)  绑定Decorator和Component的关系
    public Decorator(Component delegate) {
        this.delegate = delegate;
    }
}

【具体的装饰类-----美颜功能 】

public class MeiYanDecorator extends  Decorator {

    public MeiYanDecorator(Component delegate) {
        super(delegate);
    }

    @Override
    public void operation() {
        // 添加新的功能
        System.out.println("添加美颜功能");
        // 调用原来的功能
        delegate.operation();
    }
}

【具体的装饰类-----瘦脸功能 】

public class SouLianDecorator extends  Decorator {

    public SouLianDecorator(Component delegate) {
        super(delegate);
    }

    @Override
    public void operation() {
        // 添加新功能
        System.out.println("添加瘦脸功能");
        // 原有功能调用
        delegate.operation();
    }
}

【测试】


public class Test {

    public static void main(String[] args) {

        // 基础功能 拍照
        Component component = new ConcreteComponent();
        component.operation();

        System.out.println("");

        // 先来个美颜
        Component meiyan = new MeiYanDecorator(component);
        meiyan.operation();

        System.out.println("");

        // 美颜瘦脸 一块上
        Component meiyansoulian = new SouLianDecorator(new MeiYanDecorator(component));
        meiyansoulian.operation();


        // TODO  后面如果还需要 大眼 、表情包 ..... 各种组合
        // 构造函数的入参是 Component 接口,所以只要实现了Component接口的类都可以
        

    }
}

在这里插入图片描述

装饰者模式就是利用 构造函数 (Set方法也可以)

 public Decorator(Component delegate) {
        this.delegate = delegate;
    }

来对对象进行包装的。 这样的话,每个装饰对象的实现就和如何使用这个对象分开了,每个装饰对象只关心自己的功能,无需关心如何被天际到对象链当中。

就比如

 new SouLianDecorator(new MeiYanDecorator(component));

MeiYanDecorator包装 component,
SouLianDecorator 包装 MeiYanDecorator

当然了,我们学习这些东西要学会变通,不是说一定要有Componet 接口 ,一定要有Decorator抽象类 。

如果只有一ConcreteComponet类,没有 Component , 那么Decorator类可以是ConcreteComponet的一个子类。

反之,如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator抽象类,可以把ConcreteDecorator和Decorator合并成一个类。


装饰者模式在MyBatis中的应用

我们知道

MyBatis 的二级缓存 CachingExecutor 是在 一级缓存的基础上,动态增加了二级缓存的功能,是个标准的 装饰者模式。

在这里插入图片描述


小结

装饰者模式为已有功能动态的添加更多功能提供了一种比继承更加灵活的方式。

当系统中需要添加新的功能时,向旧的代码中添加新的代码,这些新加的代码和原有类的代码掺杂在一块,引入了不可控因素。

而装饰者模式提供了另外一个解决防范,它把要装饰的新的功能放在一个单独的类中,并让这个类包装它要装饰的对象,因此,当需要执行特殊行为时,我们就可以有选择的使用装饰功能包装对象了。

总之呢,优点如下

  • 不改变原有的代码的情况下对一个对象提供扩展功能
  • 使用不同的装饰可以组合出不同的效果
  • 符合开闭原则

非要说缺点的话,可能就是代码变多了一点

猜你喜欢

转载自blog.csdn.net/yangshangwei/article/details/106771876