设计模式-装饰器模式

概述

  • 装饰器模式(Decorator Design Pattern,也叫包装设计模式,属于结构型模式,它是作为现有的类的一个包装,允许向一个现有的对象添加新的功能,同时又不改变其结构
  • 给对象增加功能,一般两种方式继承关联组合,将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为来增强功能,这个就是装饰器模式,比继承模式更加灵活

核心思想

  • 抽象组件(Component):定义了一个接口,用于规范对象的基本行为,它是装饰器和具体组件都需要实现的接口或基类

  • 具体组件(Concrete Component)

    • Component的具体实现,也就是我们要装饰的具体对象
    • 实现了核心角色的具体对象
  • 装饰者组件(Decorator)

    • 定义具体装饰者的行为规范, 和Component角色有相同的接口,持有组件(Component)对象的实例引用
    • 主要工作就是在调用组件原有的方法之前或之后,附加额外的操作
  • 具体装饰物(Concrete Decorator):

    • 是装饰器类的实例,负责给组件添加新的行为或属性
    • 每次只有一个具体的装饰器在工作,但可以通过组合多个装饰器,一层层地包装具体组件,形成装饰链,从而实现功能的叠加

场景使用

  • GUI编程
    • 在图形用户界面编程中,装饰器模式可以用来动态地给按钮、窗口等组件添加边框、背景色、字体样式等功能。例如,可以创建一个基本按钮类,然后通过装饰器为其添加滚动条、鼠标悬浮效果、点击反馈等装饰
  • 文件系统操作
    • 对文件流(如InputStream, OutputStream)进行功能增强时,可以使用装饰器模式添加压缩、加密、缓冲等功能,如ZipInputStream、BufferedInputStream等
  • 网络请求处理
    • HTTP客户端库可能会使用装饰器模式来添加重试机制、超时控制、错误处理、日志输出等功能,每次请求都可以通过添加不同的装饰器来满足特定的需求
  • 餐饮行业点餐系统
    • 咖啡、饮品或快餐菜单中,基础产品(如原味咖啡)可通过装饰器模式添加额外的调料或配料(如糖、奶油、巧克力酱等),构建出复杂的产品组合
  • 游戏开发
    • 游戏角色能力的扩展常常使用装饰器模式,如为角色添加临时或永久的攻击提升、防御增强、速度增加等特性
  • 日志框架
    • 日志系统中,可以利用装饰器模式为原始的日志输出添加不同级别的过滤器、格式化器、远程传输器等装饰器,按需组合

优缺点

优点

  • 装饰模式与继承关系的目的都是要扩展对象的功能,但装饰模式可以提供比继承更多的灵活性
  • 使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,原有代码无须改变,符合开闭原则

缺点

  • 装饰模式增加了许多子类,如果过度使用会使程序变得很复杂 (多层包装)
  • 增加系统的复杂度,加大学习与理解的难度

装饰器模式桥接模式对比

  • 相同点都是通过封装其他对象达到设计的目的,和对象适配器也类似,有时也叫半装饰设计模式
  • 没有装饰者和被装饰者的主次区别,桥接和被桥接者是平等的,桥接可以互换,不用继承自同一个父类
  • 桥接模式不用使用同一个接口;装饰模式用同一个接口装饰,接口在父类中定义

示例

场景应用

  • 背景需求
    • 小帅由于公司发了项目奖金,不够买跑车,就先买自行车,店家里面有小号、中号、大号等规格的自行车,然后改造加一个喇叭,后来不够又要加多一个,一个防爆胎不够,又有两个,存在很多个随机组合的改装,店家就苦恼了,这样的结构难搞,价格也难算,而且需求再变动,就更麻烦了。使用装饰者就可以解决这个问题

抽象组件(Bike)

java 复制代码
public interface Bike {

    String getDescription();

    Integer getPrice();
}

具体组件(BigBike、SmallBike)

java 复制代码
public class SmallBike implements Bike{

    private String description = "小号自行车";

    @Override
    public String getDescription() {
        return description;
    }

    /**
     * 100元是小号自行车的价格
     * @return
     */
    @Override
    public Integer getPrice() {
        return 200;
    }
}
java 复制代码
public class BigBike implements Bike{

    private String description = "大号自行车";

    @Override
    public String getDescription() {
        return description;
    }

    /**
     * 200元是大号自行车的价格
     * @return
     */
    @Override
    public Integer getPrice() {
        return 200;
    }
}

装饰者组件(BikeDecorator)

java 复制代码
public class BikeDecorator implements Bike{

    private String description = "我只是装饰器,啥都不表示,子类帮我传递";

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public Integer getPrice() {
        return 0;
    }
}

具体装饰物(RSCBikeDecorator,SuonaBikeDecorator)

java 复制代码
public class RSCBikeDecorator extends BikeDecorator{

    private String description = "增加一个防爆胎";


    private Bike bike;

    public RSCBikeDecorator(Bike bike){
        this.bike = bike;
    }


    @Override
    public String getDescription() {
        return bike.getDescription() + ","+ description;
    }

    /**
     * 100 是防爆胎的价格
     * @return
     */
    @Override
    public Integer getPrice() {
        return bike.getPrice() + 100;
    }
}
java 复制代码
public class SuonaBikeDecorator extends BikeDecorator{

    private String description = "增加一个喇叭";


    private Bike bike;

    public SuonaBikeDecorator(Bike bike){
        this.bike = bike;
    }

    @Override
    public String getDescription() {
        return bike.getDescription() + ","+ description;
    }

    /**
     * 50 是唢呐喇叭的价格
     * @return
     */
    @Override
    public Integer getPrice() {
        return bike.getPrice() + 50;
    }
}

测试

小号自行车

java 复制代码
    @Test
    public void decoratorTest(){

        Bike bike = new SmallBike();
        System.out.println("description:" + bike.getDescription()+" price:"+bike.getPrice());

        BikeDecorator rscBikeDecorator = new RSCBikeDecorator(bike);
        System.out.println("description:" + rscBikeDecorator.getDescription()+" price:"+rscBikeDecorator.getPrice());

        BikeDecorator suonaBikeDecorator = new SuonaBikeDecorator(rscBikeDecorator);
        System.out.println("description:" + suonaBikeDecorator.getDescription()+" price:"+suonaBikeDecorator.getPrice());
    }

大号自行车

java 复制代码
    @Test
    public void decoratorTest(){
        Bike bike = new BigBike();
        System.out.println("description:" + bike.getDescription()+" price:"+bike.getPrice());

        BikeDecorator rscBikeDecorator = new RSCBikeDecorator(bike);
        System.out.println("description:" + rscBikeDecorator.getDescription()+" price:"+rscBikeDecorator.getPrice());

        BikeDecorator suonaBikeDecorator = new SuonaBikeDecorator(rscBikeDecorator);
        System.out.println("description:" + suonaBikeDecorator.getDescription()+" price:"+suonaBikeDecorator.getPrice());
    }
相关推荐
Goldn.1 小时前
Java核心技术栈全景解析:从Web开发到AI融合
java· spring boot· 微服务· ai· jvm· maven· hibernate
李慕婉学姐2 小时前
【开题答辩过程】以《基于Android的出租车运行监测系统设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·后端·vue
m0_740043732 小时前
SpringBoot05-配置文件-热加载/日志框架slf4j/接口文档工具Swagger/Knife4j
java·spring boot·后端·log4j
编织幻境的妖2 小时前
SQL查询连续登录用户方法详解
java·数据库·sql
未若君雅裁3 小时前
JVM面试篇总结
java·jvm·面试
kk哥88993 小时前
C++ 对象 核心介绍
java·jvm·c++
招风的黑耳3 小时前
我用SpringBoot撸了一个智慧水务监控平台
java·spring boot·后端
xunyan62343 小时前
面向对象(下)-接口的理解
java·开发语言
程序员游老板3 小时前
基于SpringBoot3+vue3的爱心陪诊平台
java·spring boot·毕业设计·软件工程·课程设计·信息与通信
期待のcode3 小时前
Springboot核心构建插件
java·spring boot·后端