跳至主要內容

结构型 - 装饰器模式(Decorator)

Zenghr大约 4 分钟设计模式设计模式

装饰(Decorator)

提示

指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式

装饰器模式介绍

装饰器器的核心就是在 不改变原有类 的基础上给类新增功能

通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会过多等问题。但是使用装饰器模式会是另外一种思路更为灵活,可以避免继承导致的子类过多

装饰器的结构

装饰器器主要解决的是直接继承下因功能的不断横向扩展导致子类膨胀的问题,而使用装饰器模式后就会比直接继承显得更加灵活同时这样也就不再需要考虑子类的维护。

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

装饰器模式主要包含以下角色:

  1. 抽象构件(Component)角色:定义一个 抽象接口 以规范准备接收附加责任的对象。
  2. 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
  3. 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  4. 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
mark
mark

装饰器的案例模拟

奶茶店中有各种各样的奶茶,珍珠奶茶、蓝莓奶茶,用户在购买时,店员会问是否要加 布丁、加糖、珍珠等配料,不同的奶茶配不同的材料,价格也不一致,使用装饰器模式设计实现。

定义抽象构件角色(Component)- 奶茶(MilkTea)

public interface MilkTea {
    /**
     * 获取最终价格
     *
     * @return 返回价格
     */
    public abstract double getPrice();
}

定义具体构件(ConcreteComponent)角色 - 珍珠奶茶(PearlTea)

// 珍珠奶茶
public class PearlTea implements MilkTea{
    @Override
    public double getPrice() {
        return 20.0;
    }
}

蓝莓奶茶(BlueberryTea)

public class BlueberryTea implements MilkTea {
    @Override
    public double getPrice() {
        return 10.0;
    }
}

定义抽象装饰(Decorator)角色 - 配料(Decorator)

public abstract class BatchingDecorator implements MilkTea {
    protected MilkTea milkTea;
}

具体装饰者 - 布丁(Pudding)

public class PuddingDecorator extends BatchingDecorator {
    public PuddingDecorator(MilkTea milkTea) {
       this.milkTea = milkTea;
    }

    @Override
    public double getPrice() {
        return 5.0 + this.milkTea.getPrice();
    }
}

具体装饰者 - 糖(Sugar)

public class SugarDecorator extends BatchingDecorator {

    public SugarDecorator(MilkTea milkTea) {
        this.milkTea = milkTea;
    }

    @Override
    public double getPrice() {
        return 3.0 + this.milkTea.getPrice();
    }
}

演示案例

我们去奶茶店买一杯蓝莓奶茶,加糖+加布丁,请问需要多少钱?

public class DecoratorExample {
    public static void main(String[] args) {
        // 蓝莓奶茶
        MilkTea milkTea = new BlueberryTea();
        // 布丁 包装类
        milkTea = new PuddingDecorator(milkTea);
        // 加糖 包装类
        milkTea = new SugarDecorator(milkTea);
        // 总价格 蓝莓10.0 + 布丁5.0 + 糖3.0 = 18.0
        System.out.println(milkTea.getPrice());
    }
}

装饰器模式的应用场景

装饰器模式通常在以下几种情况使用

  • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
  • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰器模式却很好实现。
  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

装饰器模式在 Java 中的最著名的应用莫过于 Java I/O 标准库的设计了。例如:

  • InputStream 的子类 FilterInputStream
  • OutputStream 的子类 FilterOutputStream
  • Reader 的子类 BufferedReader 以及 FilterReader
  • 还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类

如需了解 I/O 类中的装饰器模式,请看👉 Java - I/O 装饰器模式

参考资料

结构型 - 装饰(Decorator) - Java 全栈知识体系open in new window

装饰器模式详解 - C语言中文网open in new window