【设计模式】装饰器模式 在java中的应用

文章目录

      • 1. 引言
        • 装饰器模式的定义与设计目的
        • 装饰器模式与其他设计模式的比较
      • 2. 装饰器模式的结构
        • 组件接口(Component)
        • 具体组件(ConcreteComponent)
        • 装饰角色(Decorator)
        • 具体装饰类(ConcreteDecorator)
      • 3. 装饰器模式的实现
        • Java代码示例:实现一个简单的文本消息处理
        • 装饰角色(Decorator)
        • 具体装饰类(ConcreteDecorator)
        • 使用装饰器
      • 4. 装饰器模式在Java标准库中的应用
        • Java I/O库中的装饰器使用示例
        • 分析`InputStream`, `OutputStream`, `Reader`, 和 `Writer`的装饰器实现
      • 5. 装饰器模式的优缺点
        • 优点
        • 缺点
        • 设计时的考虑因素

1. 引言

装饰器模式的定义与设计目的

装饰器模式(Decorator Pattern),也称为包装器(Wrapper),是一种结构型设计模式,它允许用户在不修改现有对象结构的情况下,向对象添加新的功能。这种模式通过创建一个包装对象来包裹真实对象,从而在保持原类方法签名完整性的前提下,提供额外的功能。

设计目的

  • 扩展功能:动态地添加功能到对象上,而不改变其结构。
  • 替代子类化:在传统的继承关系中,功能的扩展通常通过创建子类实现。装饰器模式提供了一种灵活的替代方案,避免了类继承带来的复杂性和灵活性限制。
  • 组合优于继承:装饰器模式使用对象的组合方式来扩展功能,这比继承更为灵活,易于维护和扩展。
装饰器模式与其他设计模式的比较

与代理模式的比较

  • 代理模式
    • 控制对另一个对象的访问。
    • 不修改对象的行为,只是添加一层访问控制。
  • 装饰器模式
    • 动态地添加功能。
    • 直接影响对象的行为。

伪代码示例

// 装饰器模式
interface Component {void execute();
}class ConcreteComponent implements Component {public void execute() {System.out.println("Execute original behavior");}
}class Decorator implements Component {private Component wrapped;Decorator(Component comp) {this.wrapped = comp;}public void execute() {wrapped.execute();addBehavior();}private void addBehavior() {System.out.println("Add additional behavior");}
}// 代理模式
interface Subject {void execute();
}class RealSubject implements Subject {public void execute() {System.out.println("Execute original behavior");}
}class Proxy implements Subject {private Subject realSubject;Proxy(Subject sub) {this.realSubject = sub;}public void execute() {System.out.println("Proxy control before execution");realSubject.execute();System.out.println("Proxy control after execution");}
}

与适配器模式的比较

  • 适配器模式
    • 使接口不兼容的对象能够一起工作。
    • 不改变对象本身的行为,只是使其能够适应其他接口。
  • 装饰器模式
    • 增加新的功能。
    • 保持接口不变,而增加对象的职责。

伪代码示例

// 装饰器模式
// 同上述装饰器示例// 适配器模式
interface Target {void newRequest();
}class Adaptee {public void oldRequest() {System.out.println("Old request execution");}
}class Adapter implements Target {private Adaptee adaptee;Adapter(Adaptee adaptee) {this.adaptee = adaptee;}public void newRequest() {adaptee.oldRequest();}
}

2. 装饰器模式的结构

装饰器模式主要包括以下四个角色:

组件接口(Component)

组件接口定义了一个对象接口,可以动态地添加责任(功能)到对象上。在Java中,这通常是一个接口或抽象类,为装饰的对象定义最基本的功能。

public interface Component {void operation();
}
具体组件(ConcreteComponent)

具体组件是被装饰的对象,实现或继承了组件接口。它定义了基本的功能,装饰器可以给这些功能添加额外的行为。

public class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("Basic operation of ConcreteComponent.");}
}
装饰角色(Decorator)

装饰角色持有一个组件(Component)对象的引用,并定义一个与组件接口一致的接口。这样它就可以将请求转发给组件对象,并可以在转发请求前后添加新的行为。

public abstract class Decorator implements Component {protected Component component;public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}
具体装饰类(ConcreteDecorator)

具体装饰类是实现具体的装饰功能的类。它扩展了装饰角色,实现了在调用组件的方法前后可以执行额外的功能。

public class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}@Overridepublic void operation() {addedBehavior();super.operation();}private void addedBehavior() {System.out.println("Added behavior in ConcreteDecoratorA.");}
}public class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedState();}private void addedState() {System.out.println("Added state in ConcreteDecoratorB.");}
}

这种结构允许你通过添加新的装饰类在运行时动态地扩展对象的功能,而不改变原有类的代码。这是一种非常灵活的方式来增加对象的职责,同时保持代码的可读性和可维护性。

3. 装饰器模式的实现

在本节中,我们将通过Java代码示例实现一个简单的文本消息处理应用,演示如何使用装饰器模式来添加新功能,如加密和过滤敏感词。

Java代码示例:实现一个简单的文本消息处理

首先,定义一个组件接口 Message,它将具有一个方法 getContent() 来返回消息内容。

public interface Message {String getContent();
}

接下来,实现具体组件 TextMessage,它实现了 Message 接口。

public class TextMessage implements Message {private String content;public TextMessage(String content) {this.content = content;}@Overridepublic String getContent() {return content;}
}
装饰角色(Decorator)

定义抽象装饰类 MessageDecorator,它实现了 Message 接口,并持有一个 Message 对象的引用,以便对其进行装饰。

public abstract class MessageDecorator implements Message {protected Message message;public MessageDecorator(Message message) {this.message = message;}
}
具体装饰类(ConcreteDecorator)
  1. 加密装饰器 - 用于加密消息内容。
public class EncryptMessageDecorator extends MessageDecorator {public EncryptMessageDecorator(Message message) {super(message);}@Overridepublic String getContent() {return encryptContent(super.message.getContent());}private String encryptContent(String content) {// 简单的加密算法(示例用)return Base64.getEncoder().encodeToString(content.getBytes());}
}
  1. 敏感词过滤装饰器 - 用于过滤消息中的敏感词。
public class FilterMessageDecorator extends MessageDecorator {public FilterMessageDecorator(Message message) {super(message);}@Overridepublic String getContent() {return filterContent(super.message.getContent());}private String filterContent(String content) {// 简单的敏感词过滤return content.replaceAll("敏感词", "***");}
}
使用装饰器

现在,使用这些装饰器来处理文本消息:

public class DecoratorDemo {public static void main(String[] args) {Message message = new TextMessage("这是一个包含敏感词的消息");Message filteredMessage = new FilterMessageDecorator(message);Message encryptedMessage = new EncryptMessageDecorator(filteredMessage);System.out.println("原始消息: " + message.getContent());System.out.println("过滤后的消息: " + filteredMessage.getContent());System.out.println("加密后的消息: " + encryptedMessage.getContent());}
}

在这个例子中,我们首先创建了一个文本消息,然后通过一个过滤装饰器来过滤敏感词,接着通过一个加密装饰器来加密内容。这样,我们可以看到,装饰器模式使得功能扩展变得非常灵活和方便。

4. 装饰器模式在Java标准库中的应用

Java标准库中充分利用了装饰器模式,尤其是在其输入/输出(I/O)系统中。这一部分将探讨Java I/O库中装饰器模式的应用,并分析InputStreamOutputStreamReaderWriter类的装饰器实现。

Java I/O库中的装饰器使用示例

Java I/O库设计了一系列的类,用于读写数据。基类InputStreamOutputStream分别为字节流的输入和输出提供基础功能。装饰器模式在这里的应用允许用户根据需求灵活地添加功能,如缓冲、数据转换等。

示例代码

import java.io.*;public class IODemo {public static void main(String[] args) throws IOException {// 创建一个文件输入流InputStream is = new FileInputStream("example.txt");// 使用BufferedInputStream装饰文件输入流InputStream bis = new BufferedInputStream(is);// 读取数据int data = bis.read();while (data != -1) {System.out.print((char) data);data = bis.read();}// 关闭流bis.close();is.close();}
}

在这个例子中,BufferedInputStream是一个装饰器,它为FileInputStream提供了缓冲功能,从而提高了读取大文件的效率。

分析InputStream, OutputStream, Reader, 和 Writer的装饰器实现
  1. InputStreamOutputStream

    • 这些是所有字节流类的基类,提供了基本的数据读写功能。
    • 装饰器类如BufferedInputStream, BufferedOutputStream, DataInputStream, DataOutputStream等,为基本流添加了特定功能,如缓冲处理、读写基本类型数据等。
  2. ReaderWriter

    • 这些是所有字符流类的基类,用于读写字符数据。
    • 装饰器类如BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter等,提供了类似的装饰功能,但专注于字符处理。

这些装饰器类遵循开闭原则,使得原有代码不需要修改,就可以引入新的功能,展示了装饰器模式的强大灵活性。通过这种方式,Java I/O库能够提供丰富而灵活的数据处理能力,满足不同场景的需求。

5. 装饰器模式的优缺点

装饰器模式是一种非常有用的设计模式,尤其是在需要扩展对象功能而不修改原有类代码的情况下。然而,像所有设计模式一样,它也有其优势和潜在的缺点。

优点
  1. 增强功能
    装饰器模式允许动态地添加或修改对象的行为。这意味着在运行时可以根据需要增加额外的功能,而不是在编译时硬编码。

  2. 动态扩展
    由于装饰器模式允许在运行时添加功能,因此提供了极大的灵活性,使得系统可以更加动态地适应变化的需求。

  3. 遵循开闭原则
    根据开闭原则,软件实体应当对扩展开放,对修改封闭。装饰器模式允许在不修改现有对象的情况下通过添加新的装饰类来扩展对象的功能,很好地遵循了这一原则。

缺点
  1. 复杂性增加
    使用装饰器模式可能会导致设计中类的数量增加,每个类都专注于特定的功能增强。这可能会使系统结构变得更复杂,尤其是对于新来的开发者来说,理解各个类之间的关系可能会比较困难。

  2. 多层装饰可能导致系统复杂
    当多个装饰被堆叠使用时,理解和维护这样的代码可能变得更加困难。每一层装饰都会增加调用栈的深度,而且在调试时可能会使问题的追踪变得更加复杂。

  3. 性能考虑
    在某些高性能场景下,装饰器模式可能会引入额外的性能开销。每次调用装饰过的方法时,都可能涉及多个方法调用,这可能会影响到关键任务的执行时间。

尽管装饰器模式带来了设计上的多个优点,但在选择使用时应当权衡这些优缺点,并考虑是否适合当前的应用场景。在系统设计初期,合理规划和设计可以帮助避免过度使用装饰器模式带来的复杂性。

设计时的考虑因素
  1. 明确装饰器和被装饰对象的界限

    • 确保装饰器只关注于添加功能,而不改变原有对象的核心职责。
    • 被装饰对象应该能够在没有任何装饰的情况下独立运作。
  2. 保持装饰器的透明性

    • 装饰器应该实现与被装饰对象相同的接口,这样的设计使得客户代码在使用装饰后的对象时,不需要区分它是原始对象还是被装饰过的对象。
  3. 选择合适的装饰器

    • 在设计初期,考虑哪些功能是通过装饰器模式添加的最合适,避免过度使用装饰器,导致设计过于复杂。

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

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

相关文章

vue npm install出现问题

报错如下: ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: web-ifc-viewer1.0.218 npm ERR! Found: three0.149.0 npm ERR! node_modules/three npm ERR! peer three">0.126.1" from camera-controls…

爬虫项目练手

python抓取优美图库小姐姐图片 整体功能概述 这段 Python 代码定义了一个名为 ImageDownloader 的类,其主要目的是从指定网站(https://www.umei.cc)上按照不同的图片分类,爬取图片并保存到本地相应的文件夹中。不过需要注意&…

对比json数据是否变化

在 JavaScript 中,你可以使用多种方法来对比两个 JSON 数据是否发生变化。以下是几种常见的方式: 1. 使用 JSON.stringify 最简单的方法是将两个 JSON 对象序列化为字符串,并比较这些字符串。但需要注意的是,这种方法对于对象属…

C++设计模式:代理模式(Proxy)(附案例代码)

什么是代理模式? 代理模式是一种结构型设计模式,主要用于为某个对象提供一个代理,以便在不直接访问对象的情况下控制对其的访问。代理可以在客户端和目标对象之间起到一个中介的作用,添加一些额外的操作,例如权限控制…

【笔记】软技能

硬技能:操控世界的能力,处理对象为【物】。软技能:影响他人的能力,处理对象为【人】。软技能包括一个人的情商、个性、社交礼仪、沟通、语言、个人习惯,还有解决问题的能力、领导能力、时间管理能力等一切非技术能力。…

uni-app简洁的移动端登录注册界面

非常简洁的登录、注册界面模板&#xff0c;使用uni-app编写&#xff0c;直接复制粘贴即可&#xff0c;无任何引用&#xff0c;全部公开。 废话不多说&#xff0c;代码如下&#xff1a; login.vue文件 <template><view class"content"><view class&quo…

单台服务器上创建多个端口MySQL服务

单台服务器上创建多个端口MySQL服务 直接拷贝已经运行的数据库文件: # ll /data/mysql/ 总用量 204 drwxr-x--- 2 mysql mysql 4096 9月 15 2023 bin -rw-r--r-- 1 mysql mysql

【开源免费】基于SpringBoot+Vue.JS购物推荐网站(JAVA毕业设计)

博主说明&#xff1a;本文项目编号 T 073 &#xff0c;文末自助获取源码 \color{red}{T073&#xff0c;文末自助获取源码} T073&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

AI在SEO中的应用与关键词优化探讨

内容概要 在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术为搜索引擎优化&#xff08;SEO&#xff09;带来了革命性的改变。传统的SEO主要依赖于人为的经验和判断&#xff0c;而AI则通过算法分析海量数据&#xff0c;提供更加精准和高效的方式优化关键词…

Tomcat新手成长之路:安装部署优化全解析(下)

接上篇《Tomcat新手成长之路&#xff1a;安装部署优化全解析&#xff08;上&#xff09;》: link 文章目录 7.应用部署7.1.上下文7.2.启动时进行部署7.3.动态应用部署 8.Tomcat 类加载机制8.1.简介8.2.类加载器定义8.3.XML解析器和 Java 9.JMS监控9.1.简介9.2.启用 JMX 远程监…

服务器数据恢复—服务器raid0阵列硬盘指示灯显示黄颜色的数据恢复案例

服务器数据恢复环境&故障情况&#xff1a; 某品牌服务器上有一组由两块SAS硬盘组建的raid0阵列&#xff0c;上层是windows server操作系统ntfs文件系统。服务器上一个硬盘指示灯显示黄颜色&#xff0c;该指示灯对应的硬盘离线&#xff0c;raid不可用。 服务器数据恢复过程…

Ant-Design-Vue 全屏下拉日期框无法显示,能显示后小屏又位置错乱

问题1&#xff1a;在全屏后 日期选择器的下拉框无法显示。 解决&#xff1a;在Ant-Design-Vue的文档中&#xff0c;很多含下拉框的组件都有一个属性 getPopupContainer可以用来指定弹出层的挂载节点。 在该组件上加上 getPopupContainer 属性,给挂载到最外层盒子上。 <temp…

php 系统函数 记录

PHP intval() 函数 PHP函数介绍—array_key_exists(): 检查数组中是否存在特定键名 如何使用PHP中的parse_url函数解析URL PHP is_array()函数详解&#xff0c;PHP判断是否为数组 PHP函数介绍&#xff1a;in_array()函数 strpos定义和用法 strpos() 函数查找字符串在另一字符串…

Hive学习基本概念

基本概念 hive是什么&#xff1f; Facebook 开源&#xff0c;用于解决海量结构化日志的数据统计。 基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张表&#xff0c;并提供类SQL查询功能 本质是将HQL转化为MapReduce程序。 Hive处理的数据存储在H…

chrome使用问题记录

1. http自动跳转https问题 step1. 地址栏输入&#xff1a; chrome://net-internals/#hsts step2. 找到底部Delete domain security policies一栏&#xff0c;输入想处理的域名&#xff0c;点击delete。 注意&#xff1a;输入域名时去掉前缀http step3. 搞定了&#xff0c;再…

内网穿透 natapp安装与使用

前言 NATAPP是一款基于ngrok的内网穿透工具。以下是对NATAPP的详细概述&#xff1a; 基本概念 定义&#xff1a;内网穿透&#xff08;NAT穿透&#xff09;是一种技术&#xff0c;它允许具有特定源IP地址和端口号的数据包能够绕过NAT设备&#xff0c;从而被正确地路由到内网主机…

计算机光电成像理论基础

一、透过散射介质成像 1.1 光在散射介质中传输 光子携带物体信息并进行成像的过程是一个涉及光与物质相互作用的物理现象。这个过程可以分为几个步骤来理解&#xff1a; 1. **光的发射或反射**&#xff1a; - 自然界中的物体可以发射光&#xff08;如太阳&#xff09;&am…

视频监控汇聚平台Liveweb视频安防监控实时视频监控系统操作方案

Liveweb国标GB28181视频平台是一种基于国标GB/T28181协议的安防视频流媒体能力平台。它支持多种视频功能&#xff0c;包括实时监控直播、录像、检索与回看、语音对讲、云存储、告警以及平台级联等功能。该平台部署简单、可扩展性强&#xff0c;支持全终端、全平台分发接入的视频…

ASP.NET Core 9.0 静态资产传递优化 (MapStaticAssets )

一、结论 &#x1f4a2;先看结论吧&#xff0c; MapStaticAssets 在大多数情况下可以替换 UseStaticFiles&#xff0c;它已针对为应用在生成和发布时了解的资产提供服务进行了优化。 如果应用服务来自其他位置&#xff08;如磁盘或嵌入资源&#xff09;的资产&#xff0c;则应…

在 Windows 11 WSL (Ubuntu 24.04.1 LTS) | Python 3.12.x 下部署密码学库 charm

1. 在 Windows 11 上部署 Ubuntu (WSL) 由于作者没有高性能的 Ubuntu 服务器或个人电脑&#xff0c;且公司或学校提供的 Ubuntu 服务器虽然提供高性能 GPU 等硬件配置但通常不会提供 root 权限&#xff0c;因而作者通过在搭载了 Windows 11 的个人电脑上启动 Ubuntu (WSL) 来进…