装饰器模式

介绍

装饰器设计模式是结构型模式的一种,它允许向一个现有的对象添加新的功能,同时又不改变其结构。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

一般情况下,我们为了扩展一个类,常使用继承方式实现,继承会为类引入静态特征,并且随着扩展功能的增多,子类数量会越来越多。装饰器模式比继承更为灵活,可以在不增加很多子类的情况下动态扩展和撤销类的功能。

装饰器模式优点:装饰类和被装饰类可以独立发展,不会相互耦合。
装饰器模式缺点:多层装饰比较复杂,排查问题时需要层层深入比较麻烦

举例

小摊上卖的肉夹馍
一般情况下店家会提供很多种类的肉夹馍,有最简单的基础款夹馍,也有里脊肉夹馍,鸡蛋肉夹馍,牛肉肉夹馍等等。。。

将肉夹馍抽象为java 类:

/**
 * 肉夹馍抽象类,所有夹馍都需继承此类
 */
public abstract class ChineseHamburger {

    //抽象方法 返回肉夹馍的类型,由子类实现
    public abstract void getDescription();
}

使用继承

将里脊肉夹馍,牛肉肉夹馍等 抽象为 ChineseHamburger 的子类:

/**
 * 里脊肉夹馍,继承了肉夹馍抽象类
 */
public class FilletChineseHamburger extends ChineseHamburger {

    //重写 getDescription 方法,输出夹馍的类型为里脊肉
    @Override
    public void getDescription() {
        System.out.println("这是里脊肉夹馍。。。");
    }
}

使用继承方式时,店家每推出一种类型的肉夹馍,都需要创建一个 ChineseHamburger 的子类,因此子类的数量会不断增加,
而且 顾客无法个性化的选取想要的食材,只能选取菜单上已有的肉夹馍类型

结论: 使用常规的继承方式会造成类数量爆炸,且不够灵活

使用装饰器模式

实际情况下,店家只提供一种基础款肉夹馍,顾客根据自身需求添加不同种类的食材(里脊,鸡蛋,烤肠,生菜等。。),最终得到顾客想要的肉夹馍类型,每加一种食材就是对肉夹馍进行了一次包装
在这里插入图片描述

实现装饰器模式的组件

  1. Component 抽象构件
    是一个接口或者抽象类,是最原始最核心的对象,比如上面的肉夹馍抽象类 ChineseHamburger
  2. ConcreteComponent 具体构件
    Component 抽象类的基本实现类,可以单独用,也可将其进行装饰,比如上面的里脊肉夹馍
  3. Decorator 装饰角色
    一般是一个抽象类,继承自或实现 Component,它有一个指向Component 抽象构件的变量,是装饰器最关键的构件:
/**
 * 肉夹馍装饰器类
 */
public abstract class Decorator extends ChineseHamburger {

    private ChineseHamburger chineseHamburger = null;

    public Decorator(ChineseHamburger chineseHamburger){
        this.chineseHamburger = chineseHamburger;
    }

    @Override
    public void getDescription(){
        this.chineseHamburger.getDescription();
    }
}
  1. ConcreteDecorator 具体装饰角色
    EggConcreteDecorator 和 RoastSausageConcreteDecorator 是两个具体的装饰类,它们可以把基础构件装饰成新的东西,比如把一个基础肉夹馍装饰成鸡蛋或者牛肉肉夹馍
/**
 * 鸡蛋肉夹馍装饰器类
 */
public class EggConcreteDecorator extends Decorator {

    public EggConcreteDecorator(ChineseHamburger chineseHamburger) {
        super(chineseHamburger);
    }

    @Override
    public void getDescription() {
        super.getDescription();
        this.addEgg();
    }

    // 定义自己的修饰逻辑,这里是给肉夹馍加鸡蛋
    private void addEgg() {
        System.out.println("加鸡蛋。。");
    }
}
/**
 * 烤肠肉夹馍装饰器类
 */
public class RoastSausageConcreteDecorator extends Decorator{

    public RoastSausageConcreteDecorator(ChineseHamburger chineseHamburger) {
        super(chineseHamburger);
    }

    @Override
    public void getDescription() {
        super.getDescription();
        this.addRoastSausage();
    }

    // 定义自己的修饰逻辑,这里是给肉夹馍加烤肠
    private void addRoastSausage() {
        System.out.println("加烤肠。。");
    }
}

测试装饰器模式

用肉夹馍的示例来做个运行测试:

/**
 * 肉夹馍装饰器测试
 */
public class DecoratorTst {

    public static void main(String[] args) {
        //首先实例化一个基础款的里脊肉肉夹馍
        ChineseHamburger chineseHamburger = new FilletChineseHamburger();
        // 第一次修饰,加鸡蛋
        chineseHamburger = new EggConcreteDecorator(chineseHamburger);
        // 第二次修饰,加烤肠
        chineseHamburger = new RoastSausageConcreteDecorator(chineseHamburger);
        // 修饰后运行,几种食材加在一起
        chineseHamburger.getDescription();
    }

}
输出:
里脊肉夹馍。。。
加鸡蛋。。
加烤肠。。

这样就把原先的基础款里脊肉夹馍,经过两步装饰,变成了豪华版的里脊肉鸡蛋烤肠肉夹馍。


版权声明:本文为bystarf原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。