设计模式-装饰模式

文章目录

  • 一、简介
  • 二、基本概念
  • 三、装饰模式的结构和实现
    • 类图解析:
    • 装饰器的实现方式
      • 继承实现:
      • 组合实现:
      • 继承和组合对比
  • 四、装饰模式的应用场景
  • 五、与其他模式的关系
  • 六、总结

一、简介

装饰模式是一种结构型设计模式,它允许动态地向对象添加额外的功能。

二、基本概念

在这里插入图片描述

  1. 装饰模式定义:在不改变原有对象结构的情况下,通过对其进行包装拓展,以达到增强功能的目的。
  2. 装饰器角色:负责给组件对象附加额外的功能,实现了与组件具有相同接口的装饰器类。
  3. 组件角色:拥有核心功能的原始对象。
  4. 抽象组件角色:定义了组件对象的接口,可以是抽象类或接口。
  5. 具体组件角色:实现了抽象组件角色的具体对象。

三、装饰模式的结构和实现

类图解析:

// 抽象组件角色
public interface Component {
    void operation();
}

// 具体组件角色
public class ConcreteComponent implements Component {
    public void operation() {
        // 实现核心功能
        System.out.println("这是具体组件角色的核心功能");
    }
}

// 装饰器角色
public abstract class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    public void operation() {
        component.operation();
    }
}

// 具体装饰器角色
public class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }

    public void operation() {
        // 添加额外功能代码
        System.out.println("具体装饰器角色:"+"执行核心组件的功能前111");
        super.operation();
        // 添加额外功能代码
        System.out.println("具体装饰器角色:"+"执行核心组件的功能后2222");
    }
}
  1. 客户端代码示例:
Component component = new ConcreteComponent(); // 创建具体组件对象
component.operation(); // 调用核心功能

Component decoratedComponent = new ConcreteDecorator(component); // 使用具体装饰器装饰组件
decoratedComponent.operation(); // 调用增强功能

在这里插入图片描述

装饰器的实现方式

继承实现:

具体装饰器继承装饰器抽象类,通过重写父类方法实现功能拓展
  1. 继承实现方式:
// 抽象组件角色
interface Component {
    void operation();
}

// 具体组件角色
class ConcreteComponent implements Component {
    public void operation() {
        // 执行核心功能
        System.out.println("执行核心功能");
    }
}

// 抽象装饰器角色
abstract class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    public void operation() {
        component.operation();
    }
}

// 具体装饰器角色
class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    public void operation() {
        super.operation();
        // 添加额外的功能代码
        System.out.println("添加额外的功能代码A");
    }
}

class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    public void operation() {
        super.operation();
        // 添加额外的功能代码
        System.out.println("添加额外的功能代码B");
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        // 创建具体组件对象
        Component component = new ConcreteComponent();

        // 创建具体装饰器对象,并包装组件对象
        Component decoratorA = new ConcreteDecoratorA(component);
        Component decoratorB = new ConcreteDecoratorB(decoratorA);

        // 调用装饰器的操作方法,实现功能的拓展
        decoratorB.operation();
    }
}

组合实现:

具体装饰器持有装饰器抽象类的实例,通过调用实例方法实现功能拓展。
2. 组合实现方式:

// 抽象组件角色
interface Component {
    void operation();
}

// 具体组件角色
class ConcreteComponent implements Component {
    public void operation() {
        // 执行核心功能
        System.out.println("执行核心功能");
    }
}

// 装饰器角色
class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    public void operation() {
        component.operation();
    }
}

// 具体装饰器角色
class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    public void operation() {
        super.operation();
        // 添加额外的功能代码
        System.out.println("添加额外的功能代码A");
    }
}

class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    public void operation() {
        super.operation();
        // 添加额外的功能代码
        System.out.println("添加额外的功能代码B");
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        // 创建具体组件对象
        Component component = new ConcreteComponent();

        // 创建具体装饰器对象,并包装组件对象
        Component decoratorA = new ConcreteDecoratorA(component);
        Component decoratorB = new ConcreteDecoratorB(decoratorA);

        // 调用装饰器的操作方法,实现功能的拓展
        decoratorB.operation();
    }
}

这两个示例中,都有一个抽象的组件角色(Component),一个具体的组件角色(ConcreteComponent),以及几个具体的装饰器角色(ConcreteDecorator)。具体装饰器角色在构造函数中接收一个组件对象,并在自身的 operation() 方法中调用组件对象的 operation() 方法,并添加额外的功能代码。

在使用示例中,我们创建了具体组件对象和具体装饰器对象,并将它们进行组合,最后调用装饰器的 operation() 方法来实现功能的拓展。

继承和组合对比

在装饰器模式中,继承实现和组合实现是两种常见的方式。它们在实现装饰器功能时略有不同:
继承实现:

  • 优点:
    • 简单直接:通过继承抽象装饰器类,具体装饰器可以直接重写方法并添加额外功能。
    • 可复用性高:可以轻松地创建多个具体装饰器,并进行组合拓展。
  • 缺点:
    • 类爆炸:每个具体装饰器都需要创建一个新的类,当装饰器数量增多时,类的数量也会大量增加。
    • 静态结构:类的组合和功能拓展是在编译时静态决定的,无法动态地改变组合方式。

组合实现:

  • 优点:
    • 灵活组合:具体装饰器持有抽象装饰器对象,可以在运行时动态地组合不同的装饰器对象,实现不同的功能拓展组合。
    • 类结构简单:相对于继承实现,不需要创建过多的具体装饰器类,类结构相对简单。
  • 缺点:
    • 代码复杂度较高:需要在具体装饰器中额外处理抽象装饰器对象的方法调用。可能需要在抽象装饰器中定义一些默认实现,以避免空指针异常。

根据具体需求和设计考虑,可以选择适合的实现方式。继承实现适用于静态且数量有限的装饰器组合,而组合实现适用于动态和灵活的装饰器组合。两种实现方式都能实现装饰器模式的基本功能,只是在代码结构和使用方式上略有差异。

四、装饰模式的应用场景

  1. 动态添加功能:当需要在不修改现有代码的情况下,动态地给对象添加新功能时,装饰模式可以很好地满足这一需求。
  2. 避免子类爆炸:利用装饰模式,可以避免通过创建大量子类来实现各种功能组合的问题。
  3. 透明性 vs. 安全性:装饰模式中的装饰器和组件具有相同的接口,使得对于客户端而言,无需关心具体是使用了原始组件还是装饰器对象,实现了透明性。

五、与其他模式的关系

  1. 装饰模式 vs. 适配器模式:装饰模式侧重于给对象动态添加功能,而适配器模式则是为了让不兼容的类能够协同工作。
  2. 装饰模式 vs. 组合模式:装饰模式和组合模式都采用了递归组合的思想,但装饰模式着重于给对象添加功能,而组合模式着重于构建对象的树形结构。
  3. 装饰模式 vs. 桥接模式:桥接模式将抽象部分和实现部分解耦,而装饰模式则是在不改变对象结构的基础上,拓展其功能。

六、总结

装饰模式通过包装对象实现功能的动态拓展,使得系统具有更高的灵活性和可扩展性。它应用广泛,在动态添加功能、避免子类爆炸等场景都很有价值。同时,要注意使用装饰模式时,保持透明性和安全性的平衡,确保装饰器和组件具有一致的接口。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/99164.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python节假日库holidays——查询国家节假日

节假日—计算某天是否为节假日 参考学习: ​ Python holidays模块 ​ Python实现节假日查询 ​ Python怎么获取节假日信息 pip install holidaysimport holidayscn_holidays holidays.CountryHoliday(CN) print(cn_holidays)from datetime import dateif date(…

【LeetCode】剑指 Offer <二刷>(3)

目录 题目:剑指 Offer 06. 从尾到头打印链表 - 力扣(LeetCode) 题目的接口: 解题思路: 代码: 过啦!!! 题目:剑指 Offer 07. 重建二叉树 - 力扣&#xf…

2023.8.28日论文阅读

文章目录 NestFuse: An Infrared and Visible Image Fusion Architecture based on Nest Connection and Spatial/Channel Attention Models(2020的论文)本文方法 LRRNet: A Novel Representation Learning Guided Fusion Network for Infrared and Visible Images本文方法学习…

.netcore grpc截止时间和取消详解

一、截止时间概述 截止时间功能让 gRPC 客户端可以指定等待调用完成的时间。 超过截止时间时,将取消调用。 设定一个截止时间非常重要,因为它将提供调用可运行的最长时间。它能阻止异常运行的服务持续运行并耗尽服务器资源。截止时间对于构建可靠应用非…

【分享】PDF如何拆分成2个或多个文件呢?

当我们需要把一个多页的PDF文件拆分成2个或多个独立的PDF文件,可以怎么操作呢?这种情况需要使用相关工具,下面小编就来分享两个常用的工具。 1. PDF编辑器 PDF编辑器不仅可以用来编辑PDF文件,还具备多种功能,拆分PDF文…

Markdown Preview Plus Chrome插件使用

Markdown Preview Plus Chrome插件使用 1.插件说明2.插件下载3.插件配置4.文档样式4.1 网页显示4.2 导出PDF 系统:Win10 Chrome:113.0.5672.127 Markdown Preview Plus:0.7.3 1.插件说明 一般 markdown 工具自带的预览功能比较简单&#xff…

如何使用CRM系统进行精细化管理客户?

客户是企业的生命线,对客户进行精细化管理,是提高企业收益的关键。那么,如何进行客户管理?CRM系统可以实现精细化管理客户,提升客户的价值。下面我们就来详细说一说。 1、获取客户信息 Zoho CRM系统可以通过web表单、…

TS 入门

TS 入门 interface 约束作用数组的声明方式函数的定义联合类型、交叉类型、断言类型类的方面 interface 约束作用 数组的声明方式 函数的定义 联合类型、交叉类型、断言类型 类的方面 这是代码的地址: 代码的地址

Ansible学习笔记7

user模块: user模块用于管理用户账户和用户属性。 如果是windows要换一个win_user模块。 创建用户:present: [rootlocalhost ~]# ansible group1 -m user -a "nameaaa statepresent" 192.168.17.106 | CHANGED > {"ansi…

在VScode中执行npm、yarn命令报错解

在VScode中执行npm、yarn命令报错解 我使用的是vnm安装好npm,在WindowsR 界面是可以运行查看出版本的;但是在VScode中报错。 查了很多资料,我这种情况的原因是在VScode中默认使用的终端是Powershell,然后我切换到系统的cmd则可以…

11.添加侧边栏,并导入数据

修改CommonAside的代码&#xff1a; <template><div><el-menu default-active"1-4-1" class"el-menu-vertical-demo" open"handleOpen" close"handleClose":collapse"isCollapse"><!--<el-menu-it…

时序预测 | MATLAB实现基于PSO-LSTM、LSTM时间序列预测对比

时序预测 | MATLAB实现基于PSO-LSTM、LSTM时间序列预测对比 目录 时序预测 | MATLAB实现基于PSO-LSTM、LSTM时间序列预测对比效果一览基本描述程序设计参考资料 效果一览 基本描述 MATLAB实现基于PSO-LSTM、LSTM时间序列预测。 1.Matlab实现PSO-LSTM和LSTM神经网络时间序列预测…

UDS 29 认证服务

UDS协议定义了一套标准的诊断服务&#xff0c;包括会话控制、诊断请求、诊断响应和ECU编程等功能。通过UDS协议&#xff0c;诊断工具可以向ECU发送特定的请求&#xff0c;获取ECU的状态信息和故障码&#xff0c;诊断和解决故障问题。UDS是ISO 14229标准定义的一种通信协议&…

QT可执行程序打包成安装程序

目录 1.将QT程序先放到一个文件中 2.下载QtInstallerFramework-win-x86.exe 3.将setup.exe单独拷贝出来&#xff0c;进行安装测试 4.测试安装后的程序是否可执行 1.将QT程序先放到一个文件中 &#xff08;1&#xff09;QT切换到release模式&#xff0c;编译后在构建目录生…

JWT 技术的使用

应用场景&#xff1a;访问某些页面&#xff0c;需要用户进行登录&#xff0c;那我们如何知道用户有没有登录呢&#xff0c;这时我们就可以使用jwt技术。用户输入的账号和密码正确的情况下&#xff0c;后端根据用户的唯一id生成一个独一无二的token&#xff0c;并返回给前端&…

初阶数据结构(五) 栈的介绍与实现

&#x1f493;博主csdn个人主页&#xff1a;小小unicorn&#x1f493; ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的学习足迹&#x1f69a; &#x1f339;&#x1f339;&#x1f339;关注我带你学习编程知识 栈 栈的介绍栈的概念栈的结构 栈的实现…

正中优配:红筹股是啥意思?

随着我国经济的高速开展&#xff0c;越来越多的人开始参加到股票出资中。其中&#xff0c;红筹股作为一种特别类型的股票&#xff0c;备受一些出资者的关注&#xff0c;但对于一般出资者来说&#xff0c;红筹股详细含义还不是特别清楚。本文将从多个角度探讨红筹股的含义、特征…

匿名函数( lambda 表达式)

在 C 中&#xff0c;匿名函数也被称为 lambda 表达式。C11 引入了 lambda 表达式&#xff0c;使得在需要函数对象&#xff08;函数符&#xff09;的地方可以使用匿名函数来代替。 lambda 表达式的基本语法如下&#xff1a; [capture list] (parameter list) -> return typ…

解决crosstalk的方法及原理分析

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 crosstalk是干扰线与受绕线之间由于信号跳变产生的耦合电容引起的。 解决crosstalk的方法从两方面入手,一方面降低耦合电容,一方面降低timing window的overlap。 静态时序分析: 串扰延迟分析 以…

Unity编辑器扩展 | 编辑器扩展基础入门

前言 Unity编辑器扩展 | 编辑器扩展基础一、基本概念二、核心知识点 简述三、相关API 总结 前言 当谈到游戏开发工具&#xff0c;Unity编辑器是一个备受赞誉的平台。它为开发者提供了一个强大且灵活的环境&#xff0c;使他们能够创建令人惊叹的游戏和交互式体验。然而&#xf…