装饰器模式
概述
当我们编写软件时,有时我们会遇到需要在不修改现有代码的情况下添加新功能的情况。这时,我们可以使用装饰器模式。
装饰器模式是一种结构性设计模式,它允许我们在不改变对象接口的情况下动态地向对象添加功能。装饰器模式通过创建一个包装对象来实现这一目的。这个包装对象具有与原始对象相同的接口,但可以通过添加或覆盖方法来扩展或修改其行为。
装饰器模式通常用于以下情况:
- 在运行时动态地向对象添加新功能,而不会影响其他对象。
- 在不改变现有代码的情况下添加新功能。
- 以层次结构方式组合对象以获得更大的灵活性。
代码示例
下面是一个使用Java实现的装饰器模式的示例,以模拟咖啡店销售咖啡的过程。
首先,我们定义一个接口 Coffee,表示咖啡的基本特性,包括名称和价格:
public interface Coffee {String getDescription();double getCost();
}
然后,我们定义一个具体的咖啡类 SimpleCoffee,它实现了 Coffee 接口:
public class SimpleCoffee implements Coffee {@Overridepublic String getDescription() {return "Simple coffee";}@Overridepublic double getCost() {return 1.0;}
}
这个类表示最简单的咖啡,没有任何装饰。
接下来,我们定义一个装饰器类 CoffeeDecorator,它也实现了 Coffee 接口,但是它包含一个 Coffee 类型的成员变量 decoratedCoffee:
public abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee decoratedCoffee) {this.decoratedCoffee = decoratedCoffee;}@Overridepublic String getDescription() {return decoratedCoffee.getDescription();}@Overridepublic double getCost() {return decoratedCoffee.getCost();}
}
这个类的作用是让子类可以方便地覆盖 getDescription() 和 getCost() 方法,以添加额外的装饰。
接下来,我们定义两个具体的装饰器类:Milk 和 Whip,它们分别添加牛奶和奶泡:
public class Milk extends CoffeeDecorator {public Milk(Coffee decoratedCoffee) {super(decoratedCoffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + ", Milk";}@Overridepublic double getCost() {return decoratedCoffee.getCost() + 0.5;}
}public class Whip extends CoffeeDecorator {public Whip(Coffee decoratedCoffee) {super(decoratedCoffee);}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + ", Whip";}@Overridepublic double getCost() {return decoratedCoffee.getCost() + 0.7;}
}
这些类都是 CoffeeDecorator 的子类,它们实现了自己的 getDescription() 和 getCost() 方法来添加额外的功能。
最后,我们可以使用这些类来创建不同类型的咖啡,例如:
Coffee simpleCoffee = new SimpleCoffee();
System.out.println(simpleCoffee.getDescription() + " $" + simpleCoffee.getCost());Coffee coffeeWithMilk = new Milk(new SimpleCoffee());
System.out.println(coffeeWithMilk.getDescription() + " $" + coffeeWithMilk.getCost());Coffee coffeeWithMilkAndWhip = new Whip(new Milk(new SimpleCoffee()));
System.out.println(coffeeWithMilkAndWhip.getDescription() + " $" + coffeeWithMilkAndWhip.getCost());
JDK中的应用
在 Java IO 库中,许多类都使用了装饰器模式来提供更高级的功能。这些类都是在基本的输入和输出类之上建立的,通过使用不同的装饰器来组合它们,从而实现了各种不同的功能。
例如,BufferedReader 和 BufferedWriter 类就是基于装饰器模式实现的。BufferedReader 类是 Reader 类的一个装饰器,它提供了缓冲输入的功能。当我们需要从一个输入流中读取数据时,BufferedReader 将输入流中的数据读取到缓冲区中,然后逐个字符地返回它们。这样做的好处是可以减少系统调用,从而提高效率。
以下是一个使用 BufferedReader 类的示例:
FileReader fileReader = new FileReader("file.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);String line;
while ((line = bufferedReader.readLine()) != null) {System.out.println(line);
}bufferedReader.close();
fileReader.close();
在这个例子中,我们首先创建了一个 FileReader 对象来读取文件,然后将其传递给 BufferedReader 的构造函数。BufferedReader 对象使用 FileReader 对象作为其输入源,并提供了缓冲输入的功能。在 while 循环中,我们使用 readLine() 方法逐行读取文件,并打印每一行。
类似的,BufferedWriter 类也是 Writer 类的一个装饰器,它提供了缓冲输出的功能。当我们需要将数据写入到一个输出流中时,BufferedWriter 将数据写入到缓冲区中,直到缓冲区满或者我们调用 flush() 方法时,才将缓冲区中的数据写入到输出流中。
以下是一个使用 BufferedWriter 类的示例:
FileWriter fileWriter = new FileWriter("file.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);bufferedWriter.write("Hello, world!");
bufferedWriter.newLine();
bufferedWriter.write("How are you?");bufferedWriter.close();
fileWriter.close();
在这个例子中,我们首先创建了一个 FileWriter 对象来写入文件,然后将其传递给 BufferedWriter 的构造函数。BufferedWriter 对象使用 FileWriter 对象作为其输出目标,并提供了缓冲输出的功能。我们使用 write() 方法将字符串写入到缓冲区中,并使用 newLine() 方法添加一个新行。在最后,我们调用 close() 方法来关闭 BufferedWriter 和 FileWriter 对象。
通过使用装饰器模式,Java IO 库中的类可以轻松地组合成各种不同的输入和输出组合,以提供更高级的功能。
类图
当使用装饰器模式时,通常需要定义以下四种角色:
抽象组件(Component):定义了被装饰对象的基本接口。可以是一个抽象类或者接口。在 Java 中,它通常是一个接口。
具体组件(Concrete Component):实现了抽象组件接口的具体对象,也是被装饰的对象。
抽象装饰器(Decorator):维持一个指向抽象组件对象的引用,并定义了与抽象组件接口一致的接口。
具体装饰器(Concrete Decorator):向装饰对象添加额外的职责或行为。
其中,Component 定义了被装饰对象的基本接口。ConcreteComponent 实现了 Component 接口,也就是被装饰的对象。Decorator 是一个抽象类,它维持一个指向 Component 对象的引用,并定义了与 Component 接口一致的接口。ConcreteDecoratorA 和 ConcreteDecoratorB 分别是具体的装饰器类,它们继承自 Decorator 类并向被装饰对象添加额外的职责或行为。
通过组合不同的具体组件和具体装饰器,可以创建出许多不同的对象,从而提供了灵活而且可扩展的设计。
相关文章:

装饰器模式
概述 当我们编写软件时,有时我们会遇到需要在不修改现有代码的情况下添加新功能的情况。这时,我们可以使用装饰器模式。 装饰器模式是一种结构性设计模式,它允许我们在不改变对象接口的情况下动态地向对象添加功能。装饰器模式通过创建一个…...

21 Nacos客户端本地缓存及故障转移
Nacos客户端本地缓存及故障转移 在Nacos本地缓存的时候有的时候必然会出现一些故障,这些故障就需要进行处理,涉及到的核心类为ServiceInfoHolder和FailoverReactor。 本地缓存有两方面,第一方面是从注册中心获得实例信息会缓存在内存当中&a…...
遍历读取文件夹下的所有文件
遍历读取文件夹下的所有文件 例如,读取文件夹下,子文件夹的所有的jpg文件: import glob path "./database/20230302/night/*/*.jpg"#设置自己的文件夹路径以及文件 image_files glob.glob(path, recursiveTrue)for image_file …...

nexus安装与入门
安装 nexus-3.31.1-01-unix.tar.gz 链接:https://pan.baidu.com/s/1YrJMwpGxmu8N2d7XMl6fSg 提取码:kfeh 上传到服务器,解压 tar -zvxf nexus-3.31.1-01-unix.tar.gz进入bin目录,启动 ./nexus start查看状态 ./nexus status默…...

Flink SQL Checkpoint 学习总结
前言 学习总结Flink SQL Checkpoint的使用,主要目的是为了验证Flink SQL流式任务挂掉后,重启时还可以继续从上次的运行状态恢复。 验证方式 Flink SQL流式增量读取Hudi表然后sink MySQL表,任务启动后处于running状态,先查看sin…...

2023年“楚怡杯“湖南省职业院校技能竞赛“网络安全”竞赛任务书
2023年“楚怡杯“湖南省职业院校技能竞赛“网络安全”竞赛任务书 一、竞赛时间 总计:360分钟 竞赛阶段竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 180分钟 200分 A-2 本地安全策略配置 A-3 流量完整性保护 A-4 事件监控 …...
MyBatis中主键回填的两种实现方式
主键回填其实是一个非常常见的需求,特别是在数据添加的过程中,我们经常需要添加完数据之后,需要获取刚刚添加的数据 id,无论是 Jdbc 还是各种各样的数据库框架都对此提供了相关的支持,本文我就来和和大家分享下数据库主…...

Windows11如何打开ie浏览器
目录1.背景:2.方法一:在 edge 中配置使用 ie 模式3.方法二:通过 Internet 选项 打开1.背景: 昨天电脑自动从win10升级为win11了,突然发现电脑找不到ie浏览器了,打开全都是直接跳转到 edge 浏览器࿰…...

Linux:进程间通信
目录 进程间通信目的 进程间通信分类 管道 System V IPC POSIX IPC 什么是管道 站在文件描述符角度-深度理解管道 管道使用 管道通信的四种情况 管道通信的特点 进程池管理 命名管道 创建一个命名管道 命名管道的打开规则 命名管道通信实例 匿名管道与命名管道的…...
【java】将LAC改造成Elasticsearch分词插件
目录 为什么要将LAC改造成ES插件? 怎么将LAC改造成ES插件? 确认LAC java接口能work 搭建ES插件开发调试环境 编写插件 生成插件 安装、运行插件 linux版本的动态链接库生成 总结 参考文档 为什么要将LAC改造成ES插件? ES是著名的非…...
TPM 2.0实例探索3 —— LUKS磁盘加密(5)
接前文:TPM 2.0实例探索3 —— LUKS磁盘加密(4) 本文大部分内容参考: Code Sample: Protecting secret data and keys using Intel Platform... 二、LUKS磁盘加密实例 4. 将密码存储于TPM的PCR 现在将TPM非易失性存储器中保护…...

mybatisplus复习(黑马)
学习目标能够基于MyBatisPlus完成标准Dao开发能够掌握MyBatisPlus的条件查询能够掌握MyBatisPlus的字段映射与表名映射能够掌握id生成策略控制能够理解代码生成器的相关配置一、MyBatisPlus简介MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工…...

【数据聚类|深度聚类】Deep Comprehensive Correlation Mining for Image Clustering(DCCM)论文研读
Abstract 翻译 最近出现的深度无监督方法使我们能够联合学习表示和对未标记数据进行聚类。这些深度聚类方法主要关注样本之间的相关性,例如选择高精度对来逐步调整特征表示,而忽略了其他有用的相关性。本文提出了一种新的聚类框架,称为深度全面相关挖掘(DCCM),从三个方面…...
CE认证机构有哪些机构?
CE认证机构有哪些机构? 所有出口欧盟的产品都需要办理CE证明,而电子电器以及玩具是强制性要做CE认证。很多人以为只有办理欧盟NB公告机构的CE认证才可以被承认,实际上并不是。那么,除了NB公告上的机构,还有哪些认证机…...
MYSQL5.7:Access denied for user ‘root‘@‘localhost‘ (using password:YES)解决方法
一、打开MySQL目录下的my.ini文件,在文件的[mysqld]下面添加一行 skip-grant-tables,保存并关闭文件;skip-grant-tables :跳过密码登录,登录时无需密码。my.ini :一般在和bin同目录下,如果没有的话可自己创…...
单目运算符、双目运算符、三目运算符
单目运算符是什么 单目运算符是指运算所需变量为一个的运算符 又叫一元运算符,其中有逻辑非运算符:!、按位取 反运算符:~、自增自减运算符:,-等。 逻辑非运算符【!】、按位取反运算符【~】、 自…...

离线数据仓库项目搭建——准备篇
文章目录(一)什么是数据仓库(二)数据仓库基础知识(三)数据仓库建模方式(1)星行模型(2)雪花模型(3)星型模型 VS 雪花模型(四…...

十七、本地方法接口的理解
什么是本地方法? 1.简单来讲,一个Ntive method 就是一个Java调用非Java代码的接口.一个Native Method 是这样一个Java方法:该方法的实现由非Java语言实现,比如C,这个特征并非Java所特有,很多其他的编程语言都由这一机制,比如在C中…...

【halcon】模板匹配参数之金字塔级数
背景 今天,在使用模板匹配的时候,突然程序卡死,CPU直接飙到100%。最后排查发现是模板匹配其中一个参数 NumLevels 导致的: NumLevels: The number of pyramid levels used during the search is determined with numLevels. If n…...

jupyter lab安装和配置
jupyter lab 安装和配置 一、jupyter lab安装并配置 安装jupyterlab pip install jupyterlab启动 Jupyter lab默认会打开实验环境的,也可以自己在浏览器地址栏输入127.0.0.1:8888/lab 汉化 pip install jupyterlab-language-pack-zh-CN刷新一下网页࿰…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究
摘要:在消费市场竞争日益激烈的当下,传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序,探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式,分析沉浸式体验的优势与价值…...
电脑桌面太单调,用Python写一个桌面小宠物应用。
下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡,可以响应鼠标点击,并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...