Java设计模式——装饰模式

news2024/10/12 8:25:28

目录

模式动机

模式定义

模式结构

类图

代码分析

示例:动态添加功能的流

组件接口

具体组件

装饰抽象类

具体装饰类

客户端

模式分析

核心思想

动态扩展功能

组合优于继承

优点

动态扩展功能

组合优于继承

代码复用性高

符合开闭原则

缺点

增加系统的复杂性

类的膨胀

复杂的调试

适用环境

动态扩展功能

避免继承带来的类爆炸性增长

高度可定制化的需求

模式应用

输入输出流

GUI 组件

日志记录

模式扩展

多层次装饰

结合其他设计模式

总结


模式动机

一般有两种方式可以实现给一个类或对象增加行为:

  • 继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。
  • 关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)

装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。

模式定义

装饰(Decorator)模式是一种结构型设计模式,它允许在运行时动态地给一个对象添加新的职责或行为,而无需修改原有的类结构。装饰模式的核心思想是在不改变原有对象的基础上,通过组合的方式将新的职责附加到对象上。

模式结构

装饰模式包含以下几个主要角色:

  • Component(组件接口):定义了被装饰对象的接口。
  • ConcreteComponent(具体组件):实现了组件接口,定义了具体的组件对象。
  • Decorator(装饰抽象类):也实现了组件接口,持有一个对组件对象的引用,并通过组合的方式将新的职责附加到组件对象上。
  • ConcreteDecorator(具体装饰类):实现了装饰抽象类,提供了具体的装饰行为。

类图

 

代码分析

示例:动态添加功能的流

假设我们正在开发一个文本处理系统,需要支持多种文本处理功能,如加密、压缩等。我们可以使用装饰模式来实现这一需求。

组件接口
// 组件接口
interface Stream {
    void write(String data);
}
具体组件
// 具体组件:文件流
class FileStream implements Stream {
    @Override
    public void write(String data) {
        System.out.println("Writing data to file: " + data);
    }
}
装饰抽象类
// 装饰抽象类
class StreamDecorator implements Stream {
    protected Stream stream;

    public StreamDecorator(Stream stream) {
        this.stream = stream;
    }

    @Override
    public void write(String data) {
        stream.write(data);
    }
}
具体装饰类
// 具体装饰类:加密流
class EncryptedStream extends StreamDecorator {
    public EncryptedStream(Stream stream) {
        super(stream);
    }

    @Override
    public void write(String data) {
        String encryptedData = encrypt(data);
        super.write(encryptedData);
    }

    private String encrypt(String data) {
        // 加密逻辑
        return "Encrypted: " + data;
    }
}

// 具体装饰类:压缩流
class CompressedStream extends StreamDecorator {
    public CompressedStream(Stream stream) {
        super(stream);
    }

    @Override
    public void write(String data) {
        String compressedData = compress(data);
        super.write(compressedData);
    }

    private String compress(String data) {
        // 压缩逻辑
        return "Compressed: " + data;
    }
}
客户端
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Stream stream = new FileStream();
        Stream encryptedStream = new EncryptedStream(stream);
        Stream compressedStream = new CompressedStream(encryptedStream);

        compressedStream.write("Hello, World!");
    }
}

模式分析

核心思想

装饰模式的核心思想是在不改变对象自身的基础上,通过组合的方式将新的职责附加到对象上。装饰模式允许在运行时动态地给一个对象添加新的职责或行为,而无需修改原有的类结构。

动态扩展功能

装饰模式通过装饰抽象类和具体装饰类,可以在运行时动态地扩展对象的功能。具体装饰类通过继承装饰抽象类,并重写其中的方法来添加新的行为。通过这种方式,可以在不修改原有对象的基础上,灵活地扩展对象的功能。

组合优于继承

装饰模式通过组合的方式扩展对象的功能,而不是通过继承。这种方式避免了继承带来的类爆炸性增长问题,并且使得系统更加灵活和可扩展。

优点

动态扩展功能

装饰模式允许在运行时动态地给一个对象添加新的职责或行为,而无需修改原有的类结构。通过装饰模式,可以在不改变对象自身的基础上,灵活地扩展对象的功能。

组合优于继承

装饰模式通过组合的方式扩展对象的功能,而不是通过继承。这种方式避免了继承带来的类爆炸性增长问题,并且使得系统更加灵活和可扩展。

代码复用性高

装饰模式通过组合的方式扩展对象的功能,可以复用已有的组件类和装饰类,从而提高代码的复用性。

符合开闭原则

装饰模式符合开闭原则,即对扩展开放,对修改关闭。通过引入装饰抽象类和具体装饰类,可以在不修改现有代码的情况下添加新的装饰类,从而扩展系统的功能。

缺点

增加系统的复杂性

装饰模式会增加系统的复杂性,因为它引入了额外的抽象类和具体装饰类。对于简单的系统,使用装饰模式可能会显得过于复杂。

类的膨胀

如果需要添加的装饰类很多,可能会导致装饰类的数量增加,从而增加系统的维护成本。

复杂的调试

由于装饰模式通过组合的方式扩展对象的功能,可能会导致对象的层次结构变得复杂,从而增加调试的难度。

适用环境

动态扩展功能

当需要在运行时动态地给一个对象添加新的职责或行为时,可以使用装饰模式。通过装饰模式,可以在不修改对象自身的基础上,灵活地扩展对象的功能。

避免继承带来的类爆炸性增长

当需要扩展对象的功能,但不想使用继承机制时,可以使用装饰模式。通过装饰模式,可以避免继承带来的类爆炸性增长问题,并且使得系统更加灵活和可扩展。

高度可定制化的需求

当需要高度可定制化的需求时,可以使用装饰模式。通过装饰模式,可以在运行时根据用户的需要动态地添加或移除对象的功能。

模式应用

输入输出流

在 Java 中,输入输出流的实现就使用了装饰模式。例如,BufferedInputStreamDataInputStream 都是 InputStream 的装饰类,它们通过组合的方式扩展了 InputStream 的功能。

InputStream inputStream = new FileInputStream("file.txt");
InputStream bufferedInputStream = new BufferedInputStream(inputStream);
InputStream dataInputStream = new DataInputStream(bufferedInputStream);

GUI 组件

在图形用户界面(GUI)中,组件的扩展也经常使用装饰模式。例如,一个按钮组件可以通过装饰模式添加新的功能,如添加背景颜色、边框等。

Button button = new Button("Click me");
Button decoratedButton = new BackgroundColorButton(button, Color.BLUE);
Button finalButton = new BorderButton(decoratedButton, BorderStyle.SOLID);

日志记录

在日志记录系统中,可以通过装饰模式动态地添加新的日志记录方式。例如,可以将日志记录到文件、数据库或网络服务器。

Logger logger = new FileLogger();
Logger decoratedLogger = new DatabaseLogger(logger);
Logger finalLogger = new NetworkLogger(decoratedLogger);

模式扩展

多层次装饰

在某些情况下,可能需要多层次的装饰。例如,一个文本处理系统可能需要支持多种文本处理功能,如加密、压缩、编码转换等。通过多层次的装饰,可以将这些不同的功能组合在一起,从而实现高度的灵活性和可扩展性。

Stream stream = new FileStream();
Stream encryptedStream = new EncryptedStream(stream);
Stream compressedStream = new CompressedStream(encryptedStream);
Stream encodedStream = new EncodedStream(compressedStream);

结合其他设计模式

装饰模式可以与其他设计模式结合使用,以进一步提高系统的灵活性和可扩展性。例如:

  • 工厂模式:可以使用工厂模式来创建组件对象和装饰对象,从而进一步提高系统的灵活性。
  • 策略模式:可以在装饰模式的基础上使用策略模式,动态地选择不同的装饰策略。
  • 代理模式:可以在装饰模式的基础上使用代理模式,进一步增强对象的功能。

总结

  • 装饰模式用于动态地给一个对象增加一些额外的职责,就增加对象功 能来说,装饰模式比生成子类实现更为灵活。它是一种对象结构型模 式。
  • 装饰模式包含四个角色:抽象构件定义了对象的接口,可以给这些对 象动态增加职责(方法);具体构件定义了具体的构件对象,实现了 在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法); 抽象装饰类是抽象构件类的子类,用于给具体构件增加职责,但是具 体职责在其子类中实现;具体装饰类是抽象装饰类的子类,负责向构 件添加新的职责。
  • 使用装饰模式来实现扩展比继承更加灵活,它以对客户透明的方式动 态地给一个对象附加更多的责任。装饰模式可以在不需要创造更多子 类的情况下,将对象的功能加以扩展。
  • 装饰模式的主要优点在于可以提供比继承更多的灵活性,可以通过一种动态的 方式来扩展一个对象的功能,并通过使用不同的具体装饰类以及这些装饰类的 排列组合,可以创造出很多不同行为的组合,而且具体构件类与具体装饰类可 以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类;其主要缺 点在于使用装饰模式进行系统设计时将产生很多小对象,而且装饰模式比继承 更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需 要逐级排查,较为烦琐。
  • 装饰模式适用情况包括:在不影响其他对象的情况下,以动态、透明的方式给 单个对象添加职责;需要动态地给一个对象增加功能,这些功能也可以动态地 被撤销;当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展 和维护时。
  • 装饰模式可分为透明装饰模式和半透明装饰模式:在透明装饰模式中,要求客 户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该声明具体构 件类型和具体装饰类型,而应该全部声明为抽象构件类型;半透明装饰模式允 许用户在客户端声明具体装饰者类型的对象,调用在具体装饰者中新增的方法。

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

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

相关文章

内网wordpress更换IP后无法访问的解决办法

一、现象 一台装有wordpress的台式机,从一个校区移到了另一个校区,更换了IP地址,导致无法正常访问。 二、分析 安装wordpress的时候里面的ip(或域名)都已固定。安装好后,内网通过IP访问&am…

基于Maven 运行OpenRewrite的快速示例

本篇介绍一个基于Maven 运行OpenRewrite 的快速示例,展示了如何在Maven项目中使用OpenRewrite 进行代码重构。 本篇达成的效果是使用OpenRewrite 对源码自动格式化。 达成效果期望 项目中有一个类AutoFormatDemo ,类的代码如下 public class AutoFor…

ubuntu24 root用户修改密码 ubuntu新系统没有创建root用户

ubuntu 系统在虚拟机新建一个ubuntu24,但是在配置系统时候,并没有配置root密码,只是新增了一个自定义账号于密码,在创建好后,可以登录系统,设置root密码~ 1. ubuntu系统初始化后,登录自建账号 …

Nullinux:一款针对Linux操作系统的安全检测工具

关于Nullinux Nullinux是一款针对Linux操作系统的安全检测工具,广大研究人员可以利用该工具针对Linux目标设备执行网络侦查和安全检测。 该工具可以通过SMB枚举目标设备的安全状况信息,其中包括操作系统信息、域信息、共享信息、目录信息和用户信息。如…

C# 结构和类

要点: 1、结构概述 2、结构的使用 一 为什么需要结构 问题: System.Drawing.Color有很多颜色值,它是一个枚举吗? 正常人眼可分辨的颜色种类可达几十万种以上 Color提供使用RGB值返回颜色的方法 FromArgb() System.Drawing.Col…

LabVIEW开关磁阻电机特性测量系统

基于LabVIEW软件和特定硬件组件的开关磁阻电机(SRM)特性测量系统,结合多功能数据采集卡,统能够准确地测量并分析SRM的电磁特性,从而支持电机模型的精确建立和性能优化。 项目背景 在工业生产和家用电器领域&#xff0…

电子取证新视角:USB键盘流量提取密码方法研究与实现

0x01 引言 在当今数字化时代,USB设备的广泛使用使得信息安全和电子取证领域面临着新的挑战与机遇。特别是USB键盘,作为一种常见的输入设备,其流量中可能包含用户输入的敏感信息,如密码和其他私人数据。因此,研究USB键…

数据治理:制造企业转型的关键要素与战略需求

制造业,作为国民经济的主体,是立国之本、兴国之器、强国之基。从工业文明的曙光初现,到今日全球化的激烈竞争,始终昭示着一个真理:没有强大的制造业,就没有国家和民族的强盛。 为全面推进制造强国建设&…

Qt初识_项目文件解析

个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 Qt初识_项目文件解析 收录于专栏【Qt开发】 本专栏旨在分享学习Qt的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 1. pro文件解析 2.…

跟着深度学习好书实践tensorflow神经网络

前言 2024 年诺贝尔物理学奖授予了约翰霍普菲尔德 (John Hopfield)和图灵奖得主、AI教父杰弗里辛顿(Geoffrey Hinton),"以表彰他们利用人工神经网络进行机器学习的奠基性发现和发明"。 辛顿在接受电话采访…

基于Handsontable.js + Excel.js实现表格预览和导出功能(公式渲染)

本文记录在html中基于Handsontable.js Excel.js实现表格预览功能。 Handsontable官方文档 一、开发前的准备引入相关依赖库 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" co…

openpdf

1、简介 2、示例 2.1 引入依赖 <dependency><groupId>com.github.librepdf</groupId><artifactId>openpdf</artifactId><version>1.3.34</version></dependency><dependency><groupId>com.github.librepdf</…

正点原子STM32F407ZG 开发板简介

1. STM32F407ZG 学习资料 1&#xff09;ST 官方的学习资料 ST 官方资料有两个网址&#xff1a; www.stmcu.org.cn 和 www.st.com 。 www.stmcu.org.cn 是 ST 中文社区&#xff0c;里面的资料全部由 ST 中国区的人负责更新和整理&#xff0c;包含了所有 ST 公司的 …

计算机的错误计算(一百二十)

摘要 探讨在许多应用中出现的函数 的计算精度问题。 例1. 考虑在许多应用中出现的函数 计算 不妨在Python下计算&#xff1a; 若用下列Rust代码在线计算&#xff1a; fn f(x: f64) -> f64 {(x.exp() - 1.0) / x }fn main() {let result f(0.9e-13);println!("…

微知-Bluefield DPU命名规则各字段作用?BF2 BF3全系列命名大全

文章目录 背景字段命名C是bmc的意思NOT的N是是否加密S表示不加密但是secureboot enable倒数第四个都是E倒数第五个是速率 V和H是200GM表示E serials&#xff0c;H表示P serials&#xff08;区别参考兄弟篇&#xff1a;[more](https://blog.csdn.net/essencelite/article/detail…

【通信协议讲解】单片机基础重点通信协议解析与总结(IIC,CAN,MODBUS...)

目录 一.IIC总线 基础特性&#xff1a; 配置特性&#xff1a; 时序特性&#xff1a; 二.SPI总线 基础特性&#xff1a; 配置特性&#xff1a; 时序特性&#xff1a; 三.串口通信 基础特性&#xff1a; 配置特性&#xff1a; 时序特性&#xff1a; 四.CAN总线 基础特性…

vue后台管理系统从0到1(5)

文章目录 vue后台管理系统从0到1&#xff08;5&#xff09;完善侧边栏修改bug渲染header导航栏 vue后台管理系统从0到1&#xff08;5&#xff09; 接上一期&#xff0c;我们需要完善我们的侧边狼 完善侧边栏 我们在 element 组件中可以看见&#xff0c;这一个侧边栏是符合我们…

I/O进程(Day26)

一、学习内容 I/O进程 标准IO 概念 针对文件的读写操作 文件IO最终达成的目的&#xff1a;将一个临时存在于内存中的数据&#xff0c;永久性的存放于磁盘当中 操作 文件IO的操作&#xff0c;需要这样的2个指针 一个指针&#xff1a;指向源数据&#xff0c;提供读取操作的指针 …

复杂系统学习

一、复杂网络分析在复杂性研究中的地位 1.复杂系统 系统中存在的复杂度从两个维度来看 ①系统自由度&#xff08;系统组成成分的数目&#xff09; ②相互作用&#xff08;线性到非线性的转换&#xff09; 复杂网络是复杂系统的骨架 复杂系统可以抽象成一个网络&#xff0…

大数据新视界 --大数据大厂之 Dremio:改变大数据查询方式的创新引擎

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…