跳至正文
来两杯美式
返回

设计模式之装饰者模式:动态增强,比继承更有弹性

By 来两杯美式
发布于

这是 2020 年 4 月整理的设计模式专题第六篇。装饰者模式是结构型模式里”加料”思想的代表——像煎饼摊加蛋加肠一样,给对象动态叠加功能。JDK 的 I/O 流是它的经典应用。

简单说明

装饰者模式(Decorator Pattern):在不改变原有对象的基础上将功能附加到对象上,提供了比继承更有弹性的替代方案。

代码实现

有一个小吃摊,现对煎饼的售卖扩展:

/**
 * 描述:抽象的小吃类
 */
public abstract class Snack {
    protected abstract String name();
    protected abstract int price();
}

/**
 * 描述:煎饼(具体组件)
 */
public class Battercake extends Snack {
    @Override
    protected String name() {
        return "普通煎饼";
    }

    @Override
    protected int price() {
        return 10;
    }
}

/**
 * 描述:抽象的装饰者
 */
public abstract class AbstractDecorator extends Snack {
    private Snack snack;

    public AbstractDecorator(Snack battercake) {
        this.snack = battercake;
    }

    @Override
    protected String name() {
        return snack.name();
    }

    @Override
    protected int price() {
        return snack.price();
    }
}

/**
 * 描述:装饰者实现类,增强功能:加蛋
 */
public class EggDecotator extends AbstractDecorator {
    public EggDecotator(Snack snack) {
        super(snack);
    }

    @Override
    protected String name() {
        return super.name() + " 加一个蛋";
    }

    @Override
    protected int price() {
        return super.price() + 2;
    }
}

/**
 * 描述:测试类
 */
public class DecoratorTest {
    public static void main(String[] args) {
        Snack battercake = new Battercake();
        battercake = new EggDecotator(battercake);
        battercake = new EggDecotator(battercake);
        battercake = new EggDecotator(battercake);
        System.out.println(battercake.name() + " , " + battercake.price());
    }
}

输出:普通煎饼 加一个蛋 加一个蛋 加一个蛋 , 16

四个角色

动态叠加的秘密:装饰者层层包裹——new EggDecotator(new EggDecotator(new EggDecotator(new Battercake()))),每层只在上一层基础上加一点功能,且运行时自由组合、随时撤销。

装饰者 vs 继承

对比项继承装饰者
扩展方式编译期静态绑定运行期动态组合
组合爆炸加蛋/加肠/加火腿的排列组合 → 类爆炸任意叠加,类数量线性
撤销不可撤销可以撤销(去掉一层包装)
客户端感知需要知道具体子类面向抽象组件编程

为什么说比继承有弹性:如果煎饼摊要卖”加蛋、加肠、加火腿”的任意组合,继承需要为每个组合建一个子类(2³ = 8 个);装饰者只需要 3 个装饰类,任意排列组合。

适用场景与优缺点

适用场景

优点

缺点

现实中的应用

场景说明
JDK I/O 流new BufferedInputStream(new FileInputStream(...)) 层层装饰
Servlet APIHttpServletRequestWrapper / HttpServletResponseWrapper
Spring 事务对 Service 方法动态增强(本质是 AOP,装饰思想的扩展)
MyBatisCache(装饰者叠加多种缓存行为)

小结


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.软件设计原则:SOLID + KISS / YAGNI / LOD 全景
  2. 02.设计模式之原型模式,及深浅拷贝
  3. 03.设计模式之工厂模式:简单工厂、工厂方法与抽象工厂
  4. 04.设计模式之建造者模式:复杂对象的组装艺术
  5. 05.设计模式之适配器模式:让不兼容的接口协同工作
  6. 06.设计模式之桥接模式:抽象与实现分离,各自独立变化
  7. 07.设计模式之装饰者模式:动态增强,比继承更有弹性
  8. 08.设计模式之代理模式:静态代理与 JDK 动态代理
  9. 09.设计模式之外观模式:统一门面,简化子系统调用
  10. 10.设计模式之享元模式:共享细粒度对象,降低内存占用
  11. 11.设计模式之策略模式:算法家族,自由切换
  12. 12.设计模式之模板方法模式:固定骨架,可变步骤
  13. 13.设计模式之观察者模式:一对多依赖,状态变更自动通知
  14. 14.设计模式之责任链模式:请求逐级传递,动态组合处理者
  15. 15.设计模式之状态模式:状态变,行为变
  16. 16.设计模式之迭代器模式:不暴露内部实现,顺序访问集合

上一篇
设计模式之代理模式:静态代理与 JDK 动态代理
下一篇
DDD 复杂业务系统设计(八):整洁架构 vs 六边形架构 vs DDD 分层,我选哪一种