当前位置: 首页 > article >正文

结构设计模式 -装饰器设计模式 - JAVA

装饰器设计模式

    • 一. 介绍
    • 二. 代码示例
      • 2.1 抽象构件(Component)角色
      • 2.2 具体构件(Concrete Component)角色
      • 2.3 装饰(Decorator)角色
      • 2.4 具体装饰(Concrete Decorator)角色
      • 2.5 测试 结果
    • 三. 结论
      • 3.1 优缺点
      • 3.2 使用场景

前言
这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。

作者:神的孩子都在歌唱

一. 介绍

百度百科装饰模式指的是在不必改变原类文件使用继承的情况下,动态扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象

个人理解: java在编译完成后,我们无法动态的去为一个编译好的对象新增或者修改某个功能,这时候就可以通过装饰模式去设计

举例理解: 通常我们使用继承或者组合去扩展对象的行为,假如我们想要实现不同种类的手链,我们创建一个手链(Bracelet)接口,然后我们通过实现这个接口获取一个基本的手链(basic bracelet),我们可以在基本的手链的基础上进行扩展获得**金手链(Gold)和银手链(Silver)**结构图如下所示。

请添加图片描述

通过以上案例我们可以了解到,一些简单的扩展通过继承的方式就可以解决了,但如果我们还想在扩展,想要获取一个同时具备金色和银色的手链,并且还要添加某些功能,那么就会变得很复杂。如果手链类型增加,使用继承的实现逻辑就很难管理。这时候就可以通过装饰模式去设计

好了,上面的介绍都是再讲为什么要使用装饰模式,接下来就通过代码案例讲解装饰模式是怎么样子实现的,如何解决上面所说的问题

装饰模式有以下角色:

(1)抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。

(2)具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。

(3)装饰(Decorator)角色:持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。

(4)具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。

二. 代码示例

装饰模式代码具体流程如下

请添加图片描述

2.1 抽象构件(Component)角色

定义要实现的方法的接口或抽象类

/**
 * @author chenyunzhi
 * @date 2024/6/3 16:06
 * @Description 手链
 */
public interface Bracelet {

    void color();

}

2.2 具体构件(Concrete Component)角色

/**
 * @author chenyunzhi
 * @date 2024/6/3 16:08
 * @Description 基本的手链,也就是白色
 */
public class BasicBracelet implements Bracelet{
    @Override
    public void color() {
        System.out.print("基本的白色手链");
    }
}

2.3 装饰(Decorator)角色

/**
 * @author chenyunzhi
 * @date 2024/6/3 16:23
 * @Description 手链装饰器
 */
public class BraceletDecorator implements Bracelet {

    /**
     * 装饰器类应该可以访问组件变量,因此我们将保护该变量
     */
    protected Bracelet bracelet;

    public BraceletDecorator(Bracelet bracelet) {
        this.bracelet = bracelet;
    }

    @Override
    public void color() {
        this.bracelet.color();
    }
}

2.4 具体装饰(Concrete Decorator)角色

金手链

/**
 * @author chenyunzhi
 * @date 2024/6/3 16:32
 * @Description 金手链
 */
public class GoldBracelet extends BraceletDecorator{
    public GoldBracelet(Bracelet bracelet) {
        super(bracelet);
    }

    @Override
    public void color() {
        super.color();
        System.out.print(",增加金色");
    }
}

银手链

/**
 * @author chenyunzhi
 * @date 2024/6/3 16:37
 * @Description 银手链
 */
public class SilverBracelet extends BraceletDecorator{
    public SilverBracelet(Bracelet bracelet) {
        super(bracelet);
    }

    @Override
    public void color() {
        super.color();
        System.out.print(",增加银色");
    }
}

2.5 测试 结果

/**
 * @author chenyunzhi
 * @date 2024/6/3 14:39
 * @Description
 */
public class DecoratorPatternTest {
    public static void main(String[] args) throws Exception{

        // 获取金手链对象
        Bracelet goldBracelet = new GoldBracelet(new BasicBracelet());
        goldBracelet.color();

        System.out.println("\n-----------------------");

        // 获取银手链对象
        Bracelet silverBracelet = new SilverBracelet(new BasicBracelet());
        silverBracelet.color();

        System.out.println("\n-----------------------");

        // 获取包含金色和银色的手链
        Bracelet goldSilverBracelet = new GoldBracelet(new SilverBracelet(new BasicBracelet()));
        goldSilverBracelet.color();
    }
}

请添加图片描述

通过以上结果我们可以看到,如果我们想要获取包含 金色和银色的手链,可以通过组合金色和银色的装饰者对象来获取具有金色和银色手链。

三. 结论

3.1 优缺点

优点:

  • 装饰器设计模式有助于提供运行时修改能力,因此更加灵活。当选择数量较多时,易于维护和扩展。
  • 装饰器设计模式的缺点是它使用了很多相似类型的对象(装饰器)。
  • Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
  • 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

缺点

  • 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
  • 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
  • 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

3.2 使用场景

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

    不能采用继承的情况主要有两类:

    • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类定义不能继承(如final类)
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

  • 装饰器模式在Java IO类中被大量使用,例如FileReader、BufferedReader等。

作者:神的孩子都在歌唱

本人博客:https://blog.csdn.net/weixin_46654114

转载说明:务必注明来源,附带本人博客连接。


http://www.kler.cn/a/317470.html

相关文章:

  • 前端js用canvas合成图片并转file对象
  • 三周精通FastAPI:37 包含 WSGI - Flask,Django,Pyramid 以及其它
  • SpringBoot实战(三十一)集成iText5,实现RSA签署PDF
  • 【VIM】vim 常用命令
  • qt QKeySequence详解
  • zabbix监控端界面时间与服务器时间不对应
  • dockerfile案例
  • unity将多层嵌套的结构体与json字符串相互转化
  • 定制智慧科技展厅方案:哪些细节是成功的秘诀?
  • 基于报位时间判断船舶设备是否在线,基于心跳时间判断基站网络是否在线
  • Android String资源文件中,空格、换行以及特殊字符如何表示
  • 循环遍历把多维数组中的某个值改成需要的值
  • 【计算机网络 - 基础问题】每日 3 题(十一)
  • 《深度学习》—— PyTorch的介绍及PyTorch的CPU版本安装
  • 把任务管理器里面的vmware usb arbitrition停了,虚拟机一直识别不到手机设备了
  • vue上传预览CAD文件
  • Java中ArrayList和LinkedList的比较
  • 【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】
  • 第九节 Opencv自带颜色表操作
  • Unity using API openai Error en la solicitud: HTTP/1.1 400 Bad Request
  • 本地搭建我的世界服务器(JAVA)简单记录
  • JSP(Java Server Pages)基础使用
  • 打破网络安全域限制:跨区域文件传输的创新解决方案
  • Unity项目的脚本继承关系
  • 如何编写自己的Arduino库?
  • git reset 命令