设计模式-装饰器模式

发布于:2024-05-03 ⋅ 阅读:(22) ⋅ 点赞:(0)

概述

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

核心思想

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

  • 具体组件(Concrete Component)

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

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

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

在这里插入图片描述

场景使用

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

优缺点

优点

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

缺点

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

装饰器模式桥接模式对比

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

示例

场景应用

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

抽象组件(Bike)

public interface Bike {

    String getDescription();

    Integer getPrice();
}

具体组件(BigBike、SmallBike)

public class SmallBike implements Bike{

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

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

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

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

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

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

装饰者组件(BikeDecorator)

public class BikeDecorator implements Bike{

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

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

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

具体装饰物(RSCBikeDecorator,SuonaBikeDecorator)


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;
    }
}

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;
    }
}

测试

小号自行车

    @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());
    }

在这里插入图片描述

大号自行车

    @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());
    }

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到