设计模式-装饰模式

news2024/11/18 11:28:50

文章目录

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

一、简介

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

二、基本概念

在这里插入图片描述

  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. 桥接模式:桥接模式将抽象部分和实现部分解耦,而装饰模式则是在不改变对象结构的基础上,拓展其功能。

六、总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

黑客常用的10大工具介绍

黑客技术一度被认为是一个神秘的特有领域,随着技术的进步和领域环境的进步,它已经成为一种非常普遍的现象。黑客技术可以用于有害目的,也可以用于发现系统中的漏洞,并通知系统属主,帮助他们更好地保护系统。 借助于一些…

【【萌新的STM32学习--24 USART的部分介绍】】

萌新的STM32学习–24 USART的部分介绍 STM32的USART的介绍 USART 英文解释是 通用同步异步收发器 UART 通用异步收发器 USART/UART 都可以与外部设备进行全双工异步通信 USART 我们常用的也是异步通信 USART 主要特征 1.全双工异步通信 2.单线半双工通信 3.单独的发送器和接…

股市里面怎么加杠杆?买股加杠杆如何应对市场波动与风险?

股市里面怎么加杠杆?买股加杠杆如何应对市场波动与风险?首先,让我们讨论如何在股市中加杠杆。主要有一下两种方式: 1. 通过杠杆交易平台:许多券商和金融机构提供杠杆交易平台。 2. 通过杠杆型交易基金:杠…

在QGIS中手动输入坐标文本添加点状矢量要素的一种方法

目录 一、前言 二、应用场景 三、实现思路 四、实验过程 1、创建一个临时矢量图层 2、给矢量图层新增要素 3、给新增要素的几何图形赋值 4、查看要素的几何图形 五、实验总结 一、前言 本文主要为QGIS点状矢量数据编辑方面的内容,不涉及编程方面。我们知道大…

一文了解性能测试常见的指标

一、什么是性能测试 性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。 我们可以认为性能测试是:通过在测试环境下对系统或构件的性能进行探测,用以验证在生产环境下系统性能是否达到预估的性能需求…

Vue3列表竖向滚动(包含使用swiper的翻页效果)

一、使用element-plus表格进行滚动&#xff1a; 可以满足的需求&#xff1a;表格一行一行竖向滚动&#xff0c;类似走马灯。 不能满足的需求&#xff1a;表格分页竖向滚动&#xff0c;有翻页的效果。 代码&#xff1a; <template><el-table:data"tableData"…

【LeetCode-中等题】236. 二叉树的最近公共祖先

文章目录 题目方法一&#xff1a;后序遍历 回溯 题目 方法一&#xff1a;后序遍历 回溯 解题的核心就是&#xff1a;采用后序遍历 讨论p&#xff0c;q是否在当前的root的两边&#xff0c;如在两边则返回当前节点root 如何不在两边&#xff0c;只要出现一个节点等于p或者q就…

怎么让模糊的图片变清晰?试试这几招吧

有时候我们自己拍摄的照片或者是从网上下载的壁纸、头像背景等&#xff0c;应用的时候觉得这个画质怎么这么模糊&#xff0c;这种图片模糊的情况应该怎么办呐&#xff1f;其实借助专业有效的修复工具&#xff0c;我们就可以快速将模糊的图片变清晰了&#xff0c;今天就给大家介…

YOLO目标检测——人脸属性识别数据集下载分享

人脸多种属性、关键点标注数据集&#xff0c;包含了10000张脸&#xff0c;其中7500用于训练&#xff0c;2500张用于测试&#xff0c;共98个关键点。除了关键点之外&#xff0c;还有遮挡&#xff0c;姿态&#xff0c;妆容&#xff0c;光照&#xff0c; 模糊和表情等多种属性信息…

【LeetCode算法系列题解】第16~20题

CONTENTS LeetCode 16. 最接近的三数之和&#xff08;中等&#xff09;LeetCode 17. 电话号码的字母组合&#xff08;中等&#xff09;LeetCode 18. 四数之和&#xff08;中等&#xff09;LeetCode 19. 删除链表的倒数第N个节点&#xff08;中等&#xff09;LeetCode 20. 有效的…

java八股文面试[多线程]——Happens-Before规则

TODO 知识来源&#xff1a; 【23版面试突击】你知道什么是 happens-before 原则吗&#xff1f;_哔哩哔哩_bilibili 【2023年面试】Happens-Before规则是什么_哔哩哔哩_bilibili

优维×国信共研:双态交付助力国信证券持续交付更上层楼!

传统持续交付模式束缚&#xff0c;国信证券开启自主研发之路 在日益复杂的业务环境下&#xff0c;传统持续交付模式已经无法满足快速变化的需求。国信证券积极应对这一挑战&#xff0c;勇敢创新&#xff0c;突破交付瓶颈&#xff0c;实现了双态应用的持续交付新高度。 共研优…

任意文件读取

文章目录 渗透测试漏洞原理任意文件读取1. 任意文件读取概述1.1 漏洞成因1.2 漏洞危害1.3 漏洞分类1.4 任意文件读取1.4.1 文件读取1.4.2 任意文件读取1.4.3 权限问题 1.5 任意文件下载1.5.1 一般情况1.5.2 PHP实现1.5.3 任意文件下载 2. 任意文件读取攻防2.1 路径过滤2.1.1 过…

44、基于 AOP 的错误处理,相当于异常拦截处理

基于 springboot 自动配置的 spring mvc 错误处理&#xff0c;就是演示项目报错后&#xff0c;跳转到自定义的错误页面 ★ 两种错误处理方式 方式一&#xff1a; 基于Spring Boot自动配置的错误处理方式&#xff0c;只要通过属性文件即可配置错误处理行为。 提供自定义的错误…

C++ : implicit instantiation of undefined template ‘std::vector<_******>‘

编译报错 implicit instantiation of undefined template ‘std::vector<_struFontMap>’ 需要 #include add vector class

Windows安装单节点Zookeeper

刚学习Dubbo&#xff0c;在Centos7中docker安装的zookeeper3.7.1。然后在启动provider时一直报错&#xff0c;用尽办法也没有解决。然后zookeeper相关的知识虽然以前学习过&#xff0c;但是已经忘记的差不多了。现在学习dubbo只能先降低版本使用了&#xff0c;之后再复习zookee…

第二篇: libyuv的编译

一、前言 DirectShow采集出来的视频, 采集格式(例如: mjepg)和我们需要的视频格式(i420)并不一致&#xff0c;因此需要解码 二、libyuv下载 git clone https://chromium.googlesource.com/external/libyuv 三、libjpeg-turbo下载 git clone https://github.com/libjpeg-tu…

北斗三代PPP-B2b解算非组合PPP分析

下面进行了北斗三代PPP-B2b非组合PPP-B2b定位的初步结果&#xff08;具体结果参考图片红色字体&#xff0c;不要看坐标轴标注或者标题&#xff09;&#xff1a; 参考文献&#xff1a; 1、https://blog.csdn.net/qq_40056060/article/details/119107531目录系列文章目录前言一、…

基于Spring Boot的高校二手物品售卖网站设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的高校二手物品售卖网站设计与实现&#xff08;Javaspring bootMySQL&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java sp…

你需要了解的有关计算机电源的所有信息

电源单元是将插座提供的电源转换为计算机机箱内许多部件的可用电源的硬件。 它将墙上插座的交流电转换为计算机组件所需的直流电。它还通过控制电压来调节过热&#xff0c;电压可能会根据电源自动或手动变化。 电源是一个关键部件&#xff0c;因为没有它&#xff0c;其他内部…