设计模式探索:装饰器模式

1. 装饰器模式定义

装饰器模式(Decorator Pattern)

装饰器模式是一种结构型设计模式,允许向一个对象动态添加行为。在不改变类的接口的情况下,装饰器模式在原始类上增加额外的职责,并且支持多个装饰器嵌套使用。
在这里插入图片描述

装饰器模式代码示例

抽象构件类

/*** 抽象构件类* 该类声明了具体构件和装饰类中实现的业务方法,使得客户端能以一致的方式处理未装饰和已装饰对象。*/
public abstract class Component {// 抽象方法,由具体构件和装饰类实现public abstract void operation();
}

具体构件类

/*** 具体构件类* 该类实现了抽象构件类的业务方法,是被装饰的对象。*/
public class ConcreteComponent extends Component {@Overridepublic void operation() {System.out.println("ConcreteComponent: 基础功能实现");}
}

抽象装饰类

/*** 抽象装饰类* 该类是装饰者模式的核心,继承了抽象构件类,并持有一个抽象构件类型的对象引用。*/
public abstract class Decorator extends Component {// 维持一个对抽象构件对象的引用protected Component component;// 注入一个抽象构件类型的对象public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {// 调用原有业务方法component.operation();}
}

具体装饰类

/*** 具体装饰类* 该类是装饰者模式的具体实现类,向构件添加新的职责。*/
public class ConcreteDecorator extends Decorator {public ConcreteDecorator(Component component) {super(component);}@Overridepublic void operation() {super.operation(); // 调用原有业务方法addedBehavior(); // 调用新增业务方法}// 新增业务方法public void addedBehavior() {System.out.println("ConcreteDecorator: 新增业务功能");}
}

客户端使用示例

public class Client {public static void main(String[] args) {// 创建具体构件对象Component component = new ConcreteComponent();// 使用装饰类进行装饰Component decoratedComponent = new ConcreteDecorator(component);// 调用装饰后的方法decoratedComponent.operation();}
}

输出结果

ConcreteComponent: 基础功能实现
ConcreteDecorator: 新增业务功能

解析

  • 抽象构件类(Component):声明了具体构件和装饰类中实现的业务方法,使得客户端能以一致的方式处理未装饰和已装饰对象。
  • 具体构件类(ConcreteComponent):实现了抽象构件类的业务方法,是被装饰的对象。
  • 抽象装饰类(Decorator):继承了抽象构件类,持有一个抽象构件类型的对象引用,并实现了业务方法,通过调用引用对象的方法实现对业务方法的调用。
  • 具体装饰类(ConcreteDecorator):继承了抽象装饰类,实现了新增的业务方法。

通过这种设计模式,装饰器可以在不修改原始类代码的情况下,为原始类添加新的功能,并且支持多个装饰器的嵌套使用,从而灵活地增强原始类的功能。

2. 装饰器模式与代理模式的区别

代理模式(Proxy Pattern)

代理模式也是一种结构型设计模式,为其他对象提供一个代理,以控制对这个对象的访问。代理模式的主要目的是控制访问,而非增强功能。
在这里插入图片描述

  1. 目的意图不同

    • 装饰器模式:主要是为了增强目标类的功能。
    • 代理模式:主要是为了控制对目标类的访问。
  2. 使用差别

    • 装饰器模式:装饰器对目标对象没有控制权,目标对象的方法一定会被执行。
    • 代理模式:代理对象对目标对象有控制权,可以选择执行或不执行目标对象的方法。
  3. 对于客户端的关注点

    • 装饰器模式:客户端更关心的是对目标对象进行增强后的功能。
    • 代理模式:客户端更关心的是被代理对象的功能。

3. 装饰器模式在实际开发中的应用

**需求:**有多个装饰时是怎么保证后面的装饰,在前面装饰的基础上装饰的。比如字符,需要加密+压缩。怎么能让压缩,在加密的基础上压缩?

3.1 创建字符组件接口

public interface StringComponent {String transform(String str);
}

3.2 实现字符组件

// 字符组件
public class StringEncryptor implements StringComponent {@Overridepublic String transform(String str) {// base64编码return Base64.getEncoder().encodeToString(str.getBytes());}
}

3.3 字符加密装饰器

public class StringEncryptorDecorator implements StringComponent {private StringComponent component;public StringEncryptorDecorator(StringComponent component) {this.component = component;}@Overridepublic String transform(String str) {String encrypted = component.transform(str); // 调用前面一个装饰器或组件的方法// 这里演示一个简单的压缩方法,将字符串压缩成一行return encrypted.replaceAll("\\s+", "");}
}

3.4 字符压缩的装饰器

public class StringCompressorDecorator implements StringComponent {private StringComponent component;public StringCompressorDecorator(StringComponent component) {this.component = component;}@Overridepublic String transform(String str) {String compressed = component.transform(str); // 调用前面一个装饰器或组件的方法// 这里演示一个简单的压缩方法,将字符串压缩成一行return compressed.replaceAll("\\s+", "");}
}

3.5 客户端

public class Client {public static void main(String[] args) {StringComponent component = new StringEncryptor(); // 创建字符加密组件component = new StringEncryptorDecorator(component); // 用字符加密装饰器装饰它component = new StringCompressorDecorator(component); // 用字符压缩装饰器再次装饰它String original = "Hello, world!"; // 原始字符串String transformed = component.transform(original); // 转换后的字符串System.out.println(transformed);}
}

输出结果为:SGVsbG8sIHdvcmxkIQ==,这是对原始字符串进行加密和压缩后的结果。可以看到,压缩操作在加密操作的基础上进行了。

4. 装饰器模式总结

装饰器模式概述

装饰器模式是一种结构型设计模式,旨在动态地给对象添加额外的职责。

优点:

  1. 灵活性: 装饰器模式允许在运行时通过添加装饰器来扩展对象的功能,比静态继承更加灵活。
  2. 可扩展性: 可以对一个对象进行多次装饰,以实现不同的行为或功能。
  3. 低耦合度: 装饰器模式允许开发者在不修改对象本身的情况下增加新功能。
  4. 开闭原则: 符合开闭原则,即对扩展开放,对修改封闭。

缺点:

  1. 对象数量多: 装饰器模式可能会产生许多小的装饰器对象,增加系统的复杂性。
  2. 错误机会多: 由于装饰器数量可能很多,增加了出错的机会。
  3. 性能问题: 装饰器模式可能会引入额外的性能开销,尤其是在多层装饰的情况下。

适用场景:

  1. 动态添加职责: 当需要动态地给对象添加职责,而不是通过继承增加子类。
  2. 透明性: 需要保持对象的接口不变,即装饰前后对象的接口完全一致。
  3. 不支持继承: 在不支持或不便于使用继承来扩展功能的场景。

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

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

相关文章

一个php文件怎么实现联系表单自动发送邮件

学习PHP:如何编写一个自动发送邮件的联系表单处理器? 无论是反馈意见、业务咨询,还是技术支持,联系表单都能为用户提供便捷的交流途径。AokSend将探讨如何通过一个PHP文件实现联系表单的自动发送邮件功能。 php文件:…

运用F5构建机器人防御,轻松应对恶意Bot威胁

数字化加快了信息的传播与交流,网络罪犯也借机纷纷涌向线上业务。攻击者通过暴力破解、字典攻击和撞库攻击破坏身份验证,导致账户被接管、欺诈、经济损失和客户不满,对应用的影响可能是灾难性的。面对日新月异的攻击,F5分布式云机…

作业/数据结构/2024/7/8

链表的相关操作作业: 1】 按值修改 2】按值查找,返回当前节点的地址 (先不考虑重复,如果有重复,返回第一个) 3】 逆置(反转) 4】释放链表 main.c #include "head.h"int main(int argc, con…

【IMU】 温度零偏标定

温度标定 IMU的零偏随着温度的变化而变化,在全温范围内形状各异,有些可能是单调的,有些可能出现拐点。 多项式误差温度标定 目的是对估计的参数进行温度补偿,获取不同温度时的参数值(零偏、尺度、正交)&…

向github远程仓库中push,要求使用token登录

Support for password authentication was removed on August 13, 2021. Please use a personal access token instead. 如上,当向github远程仓库push时,输入github的用户名和密码出现如上错误,要求使用token登录,此时只需要用户…

SpringBoot + MyBatisPlus 实现多租户分库

一、引言 在如今的软件开发中,多租户(Multi-Tenancy)应用已经变得越来越常见。多租户是一种软件架构技术,它允许一个应用程序实例为多个租户提供服务。每个租户都有自己的数据和配置,但应用程序实例是共享的。而在我们的Spring Boot MyBati…

Celery,一个实时处理的 Python 分布式系统

大家好!我是爱摸鱼的小鸿,关注我,收看每期的编程干货。 一个简单的库,也许能够开启我们的智慧之门, 一个普通的方法,也许能在危急时刻挽救我们于水深火热, 一个新颖的思维方式,也许能…

【高校科研前沿】中国农业大学姚晓闯老师等人在农林科学Top期刊发表长篇综述:深度学习在农田识别中的应用

文章简介 论文名称:Deep learning in cropland field identification: A review(深度学习在农田识别中的应用:综述) 第一作者及单位:Fan Xu(中国农业大学土地科学与技术学院) 通讯作者及单位&…

39 线程库

目录 thread类的简单介绍线程函数参数锁线程交替打印原子性操作库无锁CAS智能指针的线程安全单例模式的线程安全 1. thread类的简单介绍 在c11之前,涉及到多线程问题,都是和平台相关的,如windows和linux下各有自己的接口,这使得…

PTA - sdut-使用函数求a+aa+aaa++⋯+aa.....aaa(n个a)之和

题目描述: 给定两个均不超过9的正整数a和n,要求:编写函数fn(a,n), 求aaaaaa⋯aa⋯aa(n个a)之和,fn须返回的是数列之和。 函数接口定义: def fn(a,n):其中, a 和 n 都是传入的参数…

《RWKV》论文笔记

原文出处 [2305.13048] RWKV: Reinventing RNNs for the Transformer Era (arxiv.org) 原文笔记 What RWKV(RawKuv):Reinventing RNNs for the Transformer Era 本文贡献如下: 提出了 RWKV 网络架构,结合了RNNS 和Transformer 的优点,同…

Java文件操作和IO的小案例

文章目录 案例1案例2案例3 案例1 要求: 扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件。 代码实现: package shixun;import java.io.File; import…

动手学深度学习54 循环神经网络

动手学深度学习54 循环神经网络 1. 循环神经网络RNN2. QA 1. 循环神经网络RNN h t h_t ht​ 与 h t − 1 h_{t-1} ht−1​ x t − 1 x_{t-1} xt−1​有关 x t x_t xt​ 与 h t h_t ht​ x t − 1 x_{t-1} xt−1​ 有关 怎么把潜变量变成RNN–假设更简单 潜变量和隐变量的区…

【动态规划Ⅴ】二维数组的动态规划——0/1矩阵、最大正方形

二维数组的动态规划——0/1矩阵、最大正方形 最大正方形1277. 统计全为 1 的正方形子矩阵221. 最大正方形 01矩阵542. 01 矩阵 最大正方形 下面两个题目是非常相似的,只是一个统计正方形数目,一个统计最大正方形的面积。 1277. 统计全为 1 的正方形子矩…

打卡第7天-----哈希表

继续坚持✊,我现在看到leetcode上的题不再没有思路了,真的是思路决定出路,在做题之前一定要把思路梳理清楚。 一、四数相加 leetcode题目编号:第454题.四数相加II 题目描述: 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j…

RoPE旋转位置编码从复数到欧拉公式

第二部分 从复数到欧拉公式 先复习下复数的一些关键概念 我们一般用表示复数,实数a叫做复数的实部,实数b叫做复数的虚部 复数的辐角是指复数在复平面上对应的向量和正向实数轴所成的有向角 的共轭复数定义为:,也可记作&#xff0…

AI发展的新方向:从卷模型到卷应用

在2024年7月4日于上海世博中心举办的世界人工智能大会暨人工智能全球治理高级别会议全体会议上,百度创始人、董事长兼首席执行官李彦宏发表了一段引人深思的演讲。他在产业发展主论坛上提出:“大家不要卷模型,要卷应用!”这句话道…

对象存储-MinIO-学习-01-安装部署

目录 一、介绍 二、环境信息 三、下载安装包 1、MinIO官网下载地址 2、选择版本 (1)MinIO Server (2)MinIO Client (3)MinIO SDK 四、MinIO SDK安装步骤 1、安装minio库 2、导入minio库报错&…

docker笔记1

docker笔记1 一、为什么要学docker?二、docker是什么三、docker安装 一、为什么要学docker? 在过去,开发人员编写的代码在不同的环境中运行时常常面临一些问题,例如“在我的机器上可以运行,但在你的机器上却不行”的情况。这种问题部分原因…

2024全网最全面及最新且最为详细的网络安全技巧五 之 SSRF 漏洞EXP技巧,典例分析以及 如何修复 (下册)———— 作者:LJS

五.SSRF 漏洞EXP技巧,典例分析以及 如何修复 (下册) 目录 五.SSRF 漏洞EXP技巧,典例分析以及 如何修复 (下册) 5.4gopher 协议初探 0x01 Gopher协议 0x02 协议访问学习 复现环境 centos7 kali 2018 发送http get请求 发送http post请求 5.5 SSRF…