装饰器模式介绍和典型实现

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许你通过将对象放入包含行为的特殊封装对象中来为原对象添加新的功能。装饰器模式的主要优点是可以在运行时动态地添加功能,而不需要修改原对象的代码。这使得代码更加灵活和可扩展。

装饰器模式的说明

角色
  1. Component(组件)

    • 定义了对象的接口,可以给这些对象动态地添加职责。
    • 可以是抽象类或接口。
  2. ConcreteComponent(具体组件)

    • 实现了 Component 接口,定义了具体的业务逻辑。
  3. Decorator(装饰器)

    • 也实现了 Component 接口,但其主要职责是为组件动态地添加功能。
    • 通常包含一个对 Component 的引用,以便调用被装饰对象的方法。
  4. ConcreteDecorator(具体装饰器)

    • 实现了 Decorator,添加了具体的功能。
  5. Client(客户端)

    • 通过 Component 接口操作对象,无需关心对象的具体类型。

经典框架中的实现案例

1. Java I/O 框架

Java I/O 框架中的 InputStreamOutputStream 类及其子类(如 BufferedInputStreamDataInputStream 等)是装饰器模式的经典应用。

  • Component(组件)InputStreamOutputStream
  • ConcreteComponent(具体组件)FileInputStreamFileOutputStream
  • Decorator(装饰器)BufferedInputStreamDataInputStreamBufferedOutputStreamDataOutputStream
  • ConcreteDecorator(具体装饰器)BufferedInputStreamDataInputStreamInputStream 添加了缓冲和数据读取功能;BufferedOutputStreamDataOutputStreamOutputStream 添加了缓冲和数据写入功能。
import java.io.*;public class JavaIOCompositeExample {public static void main(String[] args) {try {// 创建 FileInputStreamInputStream fileInputStream = new FileInputStream("input.txt");// 创建 BufferedInputStreamInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);// 创建 DataInputStreamInputStream dataInputStream = new DataInputStream(bufferedInputStream);// 读取数据int data;while ((data = dataInputStream.read()) != -1) {System.out.print((char) data);}// 关闭流dataInputStream.close();// 创建 FileOutputStreamOutputStream fileOutputStream = new FileOutputStream("output.txt");// 创建 BufferedOutputStreamOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);// 创建 DataOutputStreamOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream);// 写入数据dataOutputStream.writeBytes("Hello, World!");// 关闭流dataOutputStream.close();} catch (IOException e) {e.printStackTrace();}}
}

在这个例子中:

  • FileInputStreamFileOutputStream 是具体组件,提供基本的文件读写功能。
  • BufferedInputStreamBufferedOutputStream 是装饰器,为文件读写添加了缓冲功能。
  • DataInputStreamDataOutputStream 是具体装饰器,为文件读写添加了数据读写功能。
  • 客户端代码通过装饰器链来读写文件,而不需要关心具体的功能实现。
2. Spring AOP

Spring AOP(Aspect-Oriented Programming)框架中的切面(Aspect)和通知(Advice)可以看作是装饰器模式的应用。通过 AOP,可以在运行时动态地为方法添加额外的功能,如日志记录、事务管理等。

  • Component(组件):业务逻辑方法。
  • ConcreteComponent(具体组件):具体的业务逻辑实现。
  • Decorator(装饰器):切面(Aspect)。
  • ConcreteDecorator(具体装饰器):通知(Advice),如 @Before@After@Around 等。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;@Aspect
public class LoggingAspect {@Before("execution(* com.example.service.MyService.doSomething(..))")public void logBefore() {System.out.println("Logging before method execution");}
}public class MyService {public void doSomething() {System.out.println("Doing something in MyService");}
}public class SpringAOPCompositeExample {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(MyService.class, LoggingAspect.class);context.refresh();MyService myService = context.getBean(MyService.class);myService.doSomething();context.close();}
}

在这个例子中:

  • MyService 是具体组件,定义了具体的业务逻辑。
  • LoggingAspect 是装饰器,通过 @Before 注解为 MyServicedoSomething 方法添加了日志记录功能。
  • 客户端代码通过 Spring 容器获取 MyService 的实例,并调用其方法,而不需要关心日志记录的具体实现。

3. MyBatis 框架

MyBatis 框架中的 Interceptor 机制也可以看作是装饰器模式的应用。通过 Interceptor,可以在 SQL 执行前后添加额外的逻辑,如缓存、日志记录等。

  • Component(组件)Executor 接口。
  • ConcreteComponent(具体组件)BaseExecutor 类。
  • Decorator(装饰器)Interceptor 接口。
  • ConcreteDecorator(具体装饰器):具体的 Interceptor 实现。
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.plugin.*;import java.util.Properties;@Intercepts({@Signature(type = Executor.class, method = "update", args = {String.class, Object.class})})
public class MyInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("Intercepting before update method execution");Object result = invocation.proceed();System.out.println("Intercepting after update method execution");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 设置属性}
}public class MyBatisCompositeExample {public static void main(String[] args) {// 创建 SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = MyBatisCompositeExample.class.getClassLoader().getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// 注册 InterceptorsqlSessionFactory.getConfiguration().addInterceptor(new MyInterceptor());// 获取 SqlSessiontry (SqlSession session = sqlSessionFactory.openSession()) {// 获取 MapperUserMapper userMapper = session.getMapper(UserMapper.class);// 执行更新操作userMapper.updateUser(new User(1, "John Doe"));}}
}// User 类
public class User {private int id;private String name;public User(int id, String name) {this.id = id;this.name = name;}// Getters and Setters
}// UserMapper 接口
public interface UserMapper {void updateUser(User user);
}// mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mydb"/><property name="username" value="root"/><property name="password" value="password"/></dataSource></environment></environments><mappers><mapper resource="UserMapper.xml"/></mappers>
</configuration>// UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><update id="updateUser" parameterType="com.example.model.User">UPDATE usersSET name = #{name}WHERE id = #{id}</update>
</mapper>

在这个例子中:

  • Executor 是组件,负责执行 SQL 语句。
  • BaseExecutor 是具体组件,提供了基本的 SQL 执行功能。
  • MyInterceptor 是具体装饰器,通过 @Intercepts 注解为 Executorupdate 方法添加了日志记录功能。
  • 客户端代码通过 SqlSessionFactory 获取 SqlSession,再通过 SqlSession 获取 UserMapper,并调用其方法,而不需要关心日志记录的具体实现。

运行结果

Intercepting before update method execution
Doing something in MyService
Intercepting after update method execution

解释

  1. Component(组件)

    • Executor 接口定义了执行 SQL 语句的方法。
    • BaseExecutor 类实现了 Executor 接口,提供了基本的 SQL 执行功能。
  2. Decorator(装饰器)

    • Interceptor 接口定义了拦截器的方法。
    • MyInterceptor 类实现了 Interceptor 接口,添加了日志记录功能。
  3. ConcreteDecorator(具体装饰器)

    • MyInterceptor 通过 intercept 方法在 SQL 执行前后添加日志记录功能。
  4. Client(客户端)

    • 客户端代码通过 SqlSessionFactory 获取 SqlSession,再通过 SqlSession 获取 UserMapper,并调用其方法,而不需要关心日志记录的具体实现。

总结

  1. Java I/O 框架

    • 通过 InputStreamOutputStream 的装饰器(如 BufferedInputStreamDataInputStream)动态地添加功能,使得 I/O 操作更加灵活和高效。
  2. Spring AOP

    • 通过切面(Aspect)和通知(Advice)为方法动态地添加额外的功能,如日志记录、事务管理等,使得业务逻辑更加清晰和模块化。
  3. MyBatis 框架

    • 通过 Interceptor 机制为 SQL 执行动态地添加额外的功能,如日志记录、缓存等,使得 SQL 操作更加灵活和可扩展。

通过这些经典实现,可以看到装饰器模式在实际应用中的强大之处,它不仅简化了客户端代码,还提高了系统的可维护性和扩展性。

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

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

相关文章

【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的日志管理:Logback 的集成

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、开篇整…

神经网络知识点整理

目录 ​一、深度学习基础与流程 二、神经网络基础组件 三、卷积神经网络&#xff08;CNN&#xff09;​编辑 四、循环神经网络&#xff08;RNN&#xff09;与LSTM 五、优化技巧与调参 六、应用场景与前沿​编辑 七、总结与展望​编辑 一、深度学习基础与流程 机器学习流…

【sql优化】where 1=1

文章目录 where 11问题描述错误实现正确实现性能对比测试 where 11 问题描述 在动态 SQL 拼接场景中&#xff0c;开发者常使用 WHERE 11 简化条件拼接逻辑&#xff08;避免处理首个条件的 AND&#xff09;。理论上&#xff0c;数据库优化器会忽略 11&#xff0c;但字符串拼接…

车载以太网网络测试 -24【SOME/IP概述】

目录 1 摘要2 车载SOME/IP 概述2.1发展背景以及应用2.1.1车载 SOME/IP 背景2.1.2 车载 SOME/IP 应用场景 2.3 什么是SOME/IP2.3.1 SOME/IP定义2.3.2 SOME/IP在协议栈中的位置 3 SOA是什么4 SOME/IP主要功能5 SOME/IP标准 1 摘要 本文主要介绍SOME/IP的背景以及在车载行业的发展…

vue3中,route4,获取当前页面路由的问题

首先应用场景如下&#xff1a; 在main.js里面&#xff0c;引入的是路由的配置文件&#xff0c;如下&#xff1a; import {router} from /router; app.use(router); 路由配置文件router.js如下&#xff1a; import { createRouter, createWebHistory } from vue-router; imp…

ip改变导致的数据库连接不上

前言 需要用到路由器&#xff0c;所以先把家里的路由器给拆了先用着。新的路由器到了之后&#xff0c;更换上新的路由器之后&#xff0c;调用到服务会有报错&#xff0c;记录一下更换路由器之后ip重新分配服务可能会报的错. 进一步可以看到有关网路在服务当中的影响。 正文 …

Chrome 开发环境快速屏蔽 CORS 跨域限制!

Chrome 开发环境快速屏蔽 CORS 跨域限制【详细教程】 ❓ 为什么需要临时屏蔽 CORS&#xff1f; 在前后端开发过程中&#xff0c;我们经常会遇到 跨域请求被浏览器拦截 的问题。例如&#xff0c;你在 http://localhost:3000 调用 https://api.example.com 时&#xff0c;可能会…

【力扣hot100题】(009)和为K的子数组

还是太菜了&#xff08;我&#xff09;&#xff0c;写了半天滑动窗口&#xff0c;然后看了答案又写了半天时间超限…… 总之就是记录每前n个子串的和&#xff0c;然后使用hash存储和为某个值出现的次数&#xff0c;每次求得新和就看看是否存在前面新和-k的字符&#xff0c;有的…

使用 rsync 进行服务器文件同步与优化

使用 Rsync 工具在两台 Linux 服务器之间同步文件 Rsync 是一种高效的文件同步工具&#xff0c;它可以在本地或远程服务器之间同步文件和目录。Rsync 通过仅传输文件的变化部分来减少数据传输量&#xff0c;因此特别适合用于定期备份或同步大量数据。本文将详细介绍如何将 A 服…

卷积神经网络 - 微步卷积、空洞卷积

一、微步卷积 微步卷积&#xff08;Fractionally Strided Convolution&#xff09;&#xff0c;通常也称为转置卷积&#xff08;Transposed Convolution&#xff09;或反卷积&#xff08;Deconvolution&#xff09;&#xff0c;是深度学习&#xff08;尤其是卷积神经网络&…

详解java体系实用知识总结

0.java技术能力框架 基础模块应用模块综合模块技术岗位与面试流程常用工具集系统架构设计计算机基础常用框架微服务架构jvm原理缓存容器化多线程队列云计算&#xff08;阿里云/aws&#xff09;设计模式数据库数据结构与算法 1.常用设计模式与应用场景 工厂模式&#xff1a;s…

设计模式之创建型5种

设计模式 为什么设计模式是23种创建型 对象创建为什么设计模式是23种 设计模式之所以被归纳为23种,而非其他数量,源于GoF(Gang of Four)在1994年的系统性总结和分类。这一数量的确定并非偶然,而是基于以下核心原因: 他们遵循“大三律”(Rule of Three),即只有经过三个…

Oracle 23ai Vector Search 系列之2 ONNX(Open Neural Network Exchange)

文章目录 Oracle 23ai Vector Search 系列之2 ONNX(Open Neural Network Exchange)ONNX基本概念ONNX(Open Neural Network Exchange)ONNX Runtime ONNX Runtime 在Oracle数据库中的集成参考 Oracle 23ai Vector Search 系列之2 ONNX(Open Neural Network Exchange) 我们在看【…

统一语言学习范式

摘要 现有的预训练模型通常针对特定类别的问题。迄今为止&#xff0c;关于何种架构和预训练设置应为最佳似乎仍未达成共识。本文提出了一个统一的框架&#xff0c;用于预训练在多种数据集和设置中普遍有效的模型。我们首先将架构原型与预训练目标这两个常被混为一谈的概念进行…

Flutter项目升级到指定版本的详细步骤指南

一、升级前的准备工作 备份项目 使用Git提交当前所有修改&#xff1a;git commit -am "Pre-upgrade backup"或直接复制项目文件夹 查看当前环境信息 flutter --version flutter doctor二、升级Flutter SDK到指定版本 方法1&#xff1a;通过版本管理工具升级&#x…

22、web前端开发之html5(三)

六. 离线存储与缓存 在网络环境不稳定或需要优化资源加载速度的场景下&#xff0c;离线存储与缓存技术显得尤为重要。HTML5引入了多种离线存储和缓存机制&#xff0c;帮助开发者提升用户体验。本节将详细介绍Application Cache、localStorage、sessionStorage以及IndexedDB等技…

用HTML和CSS生成炫光动画卡片

这个效果结合了渐变、旋转和悬浮效果的炫酷动画示例&#xff0c;使用HTML和CSS实现。 一、效果 二、实现 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport&quo…

【嵌入式学习2】数组

目录 ## 数组概念 ## 数组使用 ## 数组初始化 ## 数组名 ## 数组长度 ## 数组相关题目 1、找最大值 2、逆置 ## 数组和指针 指针加整数的含义 ## 指针数组 ## 数组名做函数参数 ## 函数参数传递数组 1、在函数内部 2. 在函数外部 ## 多维数组 使用下标访问 #…

C++中的判断与循环

一.if判断语句 1.程序中的判断&#xff1a; if (要执行的判断&#xff0c;最后的返回值要是bool型的数据) {如果为真&#xff0c;要执行的代码段; } #include"iostream" using namespace std;int main() {int ans;cin >> ans;if (ans > 1000) {cout <…

前端开发中生成网站的favicon.ico文件的软件推荐及使用方法

日常网站开发中&#xff0c;我们经常需要生成网站的favicon.ico文件&#xff0c;今天我在这里来推荐几个编辑.ico(也可将图片格式转化为.ico)图片&#xff0c;而且免费的那软件&#xff1a; GIMP&#xff1a;一个功能强大的开源图像编辑软件&#xff0c;支持多种文件格式&#…