设计模式-装饰器模式

概述

  • 装饰器模式(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());
    }
相关推荐
积水成江1 小时前
Vite+Vue3+SpringBoot项目如何打包部署
java·前端·vue.js·windows·spring boot·后端·nginx
CocoaAndYy2 小时前
ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal原理及Demo
java·jvm·算法
2401_857439693 小时前
SpringBoot在线教育平台:设计与实现的深度解析
java·spring boot·后端
总是学不会.3 小时前
SpringBoot项目:前后端打包与部署(使用 Maven)
java·服务器·前端·后端·maven
IT学长编程3 小时前
计算机毕业设计 视频点播系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·视频点播系统
一 乐4 小时前
英语词汇小程序小程序|英语词汇小程序系统|基于java的四六级词汇小程序设计与实现(源码+数据库+文档)
java·数据库·小程序·源码·notepad++·英语词汇
曳渔5 小时前
Java-数据结构-反射、枚举 |ू・ω・` )
java·开发语言·数据结构·算法
laocooon5238578865 小时前
java 模拟多人聊天室,服务器与客户机
java·开发语言
风槐啊5 小时前
六、Java 基础语法(下)
android·java·开发语言
苹果醋35 小时前
毕业设计_基于SpringBoot+vue的社区博客系统【源码+SQL+教程+可运行】41002
java·毕业设计·博客