装饰器模式---- 不修改原始对象,给原对象增加新的行为和功能。

2.1、概念

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许动态地向对象添加额外的功能,而无需修改其原始代码。核心思想是可以动态地为对象添加额外的功能,而不需要修改对象本身的代码。这个模式中,我们通过创建一个装饰器类来包装某个具体的组件实现,并增加一些额外的功能。由于装饰器类与被装饰者实现了相同的接口,因此它可以替代被装饰者,并且可以在运行时动态地为被装饰者添加额外的功能。

装饰器模式的核心思想是基于组合的方式实现功能的扩展,它与继承相比,更加灵活和可扩展。通过使用装饰器模式,我们可以避免对原始对象进行修改,并能够动态地为对象添加新的功能,从而使得软件设计更加灵活和易于维护。

2.2、实现代码

下面是Java中装饰器模式的简单实现:

// 定义组件接口
public interface Component {void operation();
}// 具体组件实现类
public class ConcreteComponent implements Component {
@Override
public void operation() {System.out.println("执行具体组件操作");
}
}// 装饰器类
public class Decorator implements Component {private Component component; // 维持对被装饰者对象的引用public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation(); // 调用被装饰者对象的方法}
}// 具体装饰器类A
public class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}@Overridepublic void operation() {super.operation(); // 调用父类的方法System.out.println("为具体组件A增加额外功能");}
}// 具体装饰器类B
public class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}@Overridepublic void operation() {super.operation(); // 调用父类的方法System.out.println("为具体组件B增加额外功能");}
}

在上面的示例中,我们首先定义了一个Component接口和一个ConcreteComponent实现类,后者提供了基础的功能。然后,我们定义了一个Decorator装饰器类,并在其中包装了一个Component类型的引用,该类实现了Component接口并提供了与被装饰者相同的行为。

接下来,我们又定义了两个具体装饰器类ConcreteDecoratorA和ConcreteDecoratorB,这两个类分别向原始的ConcreteComponent组件添加不同的额外功能。

最后,我们可以通过如下代码使用装饰器模式:

Component component = new ConcreteComponent();
Component decoratorA = new ConcreteDecoratorA(component);
Component decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB.operation();

在这个示例中,我们首先创建了一个ConcreteComponent实例,并将其作为参数传递给装饰器类ConcreteDecoratorA和ConcreteDecoratorB。最后,我们调用了decoratorB的operation方法,它会依次调用ConcreteDecoratorA、ConcreteDecoratorB和ConcreteComponent的operation方法,从而实现了多个功能的组合。通过装饰器模式,我们可以实现动态地向对象添加额外的功能,这样可以让代码更加灵活和可扩展。但是需要注意,如果装饰器过多或者过于复杂,可能会导致代码难以维护。

2.3、如何落地

2.3.1、拦截器中的实现

装饰器模式一般的使用场景:例如在运行时给原方法添加日志、缓存、权限控制、安全认证及监控等。

在Spring MVC项目中,装饰器模式通常用于实现拦截器(Interceptor)功能。拦截器是一种常见的AOP技术,它可以在处理请求之前或之后执行某些操作。

下面是一个简单的示例代码,演示了如何使用装饰器模式实现Spring MVC中的拦截器功能:

首先,定义一个接口HandlerInterceptor作为被装饰者,它包含三个方法:preHandle、postHandle和afterCompletion,这些方法分别对应请求处理前、请求处理后和请求完成后的操作。

public interface HandlerInterceptor {boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception;void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;
}

然后,定义一个抽象类HandlerInterceptorDecorator作为装饰器类,它继承自HandlerInterceptor接口并添加了一个protected类型的成员变量decorated,该变量表示被装饰的对象。此外,该类还提供了一个构造函数,用于初始化成员变量。

public abstract class HandlerInterceptorDecorator implements HandlerInterceptor {protected HandlerInterceptor decorated;public HandlerInterceptorDecorator(HandlerInterceptor decorated) {this.decorated = decorated;}
}

接着,我们可以定义一些具体的装饰器类,例如SecurityInterceptor、LoggingInterceptor和PerformanceMonitorInterceptor,这些类都继承自HandlerInterceptorDecorator类,并重写了父类中的方法以提供额外的功能。

public class SecurityInterceptor extends HandlerInterceptorDecorator {public SecurityInterceptor(HandlerInterceptor decorated) {super(decorated);}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 在请求处理前执行安全检查return super.preHandle(request, response, handler);}
}public class LoggingInterceptor extends HandlerInterceptorDecorator {public LoggingInterceptor(HandlerInterceptor decorated) {super(decorated);}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 在请求处理后记录日志super.postHandle(request, response, handler, modelAndView);}
}public class PerformanceMonitorInterceptor extends HandlerInterceptorDecorator {public PerformanceMonitorInterceptor(HandlerInterceptor decorated) {super(decorated);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 在请求完成后记录性能统计信息super.afterCompletion(request, response, handler, ex);}
}

最后,在Spring MVC配置文件中,我们可以将多个拦截器按顺序组合起来,并将它们应用于特定的请求路径:

<mvc:interceptors><bean id="securityInterceptor" class="com.example.SecurityInterceptor"><constructor-arg ref="loggingInterceptor"/></bean><bean id="loggingInterceptor" class="com.example.LoggingInterceptor"><constructor-arg ref="performanceMonitorInterceptor"/></bean><bean id="performanceMonitorInterceptor" class="com.example.PerformanceMonitorInterceptor"><constructor-arg ref="defaultHandlerInterceptor"/></bean><bean id="defaultHandlerInterceptor" class="org.springframework.web.servlet.handler.HandlerInterceptorAdapter"/>
</mvc:interceptors>

在这个示例中,我们首先创建了多个装饰器类,例如SecurityInterceptor、LoggingInterceptor和PerformanceMonitorInterceptor,它们都继承自HandlerInterceptorDecorator并重写了父类中的方法以提供额外的功能。然后,我们通过Spring MVC配置文件将这些拦截器按顺序组合起来,并将它们应用于特定的请求路径。通过使用装饰器模式,我们可以实现动态地为对象添加新的功能,从而让代码更加灵活和可扩展。

2.3.2、InputStream中的实现

以下是InputStream、BufferedInputStream和DataInputStream的源代码分析,以展示它们是如何使用装饰器模式来扩展InputStream类的功能。

InputStream类

InputStream是一个抽象类,它提供了从输入源读取字节的方法。以下是InputStream类的源代码片段:

public abstract class InputStream implements Closeable {public abstract int read() throws IOException;public int read(byte b[], int off, int len) throws IOException {// ...}public long skip(long n) throws IOException {// ...}public int available() throws IOException {// ...}public void close() throws IOException {// ...}
}

FilterInputStream类

FilterInputStream类,它是所有装饰器类的基类,该类继承自InputStream类。以下是FilterInputStream类的源代码片段:

public  class FilterInputStream extends InputStream {protected volatile InputStream in;protected FilterInputStream(InputStream in) {this.in = in;}public int read() throws IOException;public int read(byte b[], int off, int len) throws IOException {// ...}public long skip(long n) throws IOException {// ...}public int available() throws IOException {// ...}public void close() throws IOException {// ...}
}

FilterInputStream类是InputStream的一个子类,并且实现了InputStream的所有方法。FilterInputStream类通过装饰器模式来扩展InputStream类的功能,可以在读取数据时对数据进行过滤、处理或包装。

FilterInputStream类的构造函数需要传入一个InputStream对象作为参数,这个InputStream对象是需要被装饰的底层输入流。FilterInputStream类添加了若干个字段和方法,用于扩展InputStream类的功能。

BufferedInputStream类

BufferedInputStream继承自FilterInputStream类,该类本身继承自InputStream类。以下是BufferedInputStream类的源代码片段:

public class BufferedInputStream extends FilterInputStream {protected volatile byte buf[];protected int count;protected int pos;protected int markpos = -1;protected int marklimit;public BufferedInputStream(InputStream in, int size) {super(in);if (size <= 0) {throw new IllegalArgumentException("Buffer size <= 0");}buf = new byte[size];}// ...public synchronized int read() throws IOException {// ...}public synchronized int read(byte[] b, int off, int len)throws IOException {// ...}// ...
}

可以看到,BufferedInputStream将底层的InputStream对象通过构造函数传递进来,并存储在FilterInputStream类中的in字段中。它添加了一个缓存区(buf)和一些额外的状态变量,以实现对数据的预先加载、减少I/O操作次数和提高读取效率的目的。BufferedInputStream的read()方法会先从缓存区中读取数据,如果缓存区为空,则从底层的InputStream对象中读取一定数量的字节并缓存起来。

DataInputStream类

DataInputStream也是一个装饰器模式的实现。以下是DataInputStream类的源代码片段:

public class DataInputStream extends FilterInputStream implements DataInput {// ...public final boolean readBoolean() throws IOException {// ...}public final byte readByte() throws IOException {// ...}public final short readShort() throws IOException {// ...}public final int readInt() throws IOException {// ...}public final long readLong() throws IOException {// ...}public final float readFloat() throws IOException {// ...}public final double readDouble() throws IOException {// ...}public final String readUTF() throws IOException {// ...}// ...
}

可以看到,DataInputStream继承自FilterInputStream类,并添加了额外的方法如readByte,用于将输入流中的数据解码成基本数据类型和字符串。它实现了DataInput接口,该接口定义了许多用于解析二进制数据的方法。DataInputStream的构造函数也需要将底层的InputStream对象传递进来,并存储在FilterInputStream类中的in字段中。

============================================================

如果文章对你有帮助,不要忘记加个关注、点个赞!!!必回关!!!

从原理到实践:装饰器模式如何在项目中落地详解(给原对象增加新的行为和功能)相关推荐

  1. 装饰器模式在 Collections 类中的应用

    我们前面讲到,Java IO 类库是装饰器模式的非常经典的应用.实际上,Java 的 Collections 类也用到了装饰器模式. Collections 类是一个集合容器的工具类,提供了很多静态方 ...

  2. php设计模式八-----装饰器模式

    1.介绍: 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...

  3. Mybatis源码:Cache 装饰器模式

    装饰器模式介绍 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个 ...

  4. go设计模式之装饰器模式

    go设计模式之装饰器模式 再写这篇文章时,我已经看了很多其他人发表的类似文章,大概看了这么多吧. 亓斌的设计模式-装饰者模式(Go语言描述) jeanphorn的Golang设计模式之装饰模式 七八月 ...

  5. 设计模式笔记十:装饰器模式

    原文:http://www.runoob.com/design-pattern/ (大部分摘抄) 少许个人理解,如有错误请指出.欢迎一起讨论. 装饰器模式(Decorator Pattern) 允许向 ...

  6. 设计模式--装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装.简单来说,装饰器模式就是 ...

  7. Java设计模式学习总结(11)——结构型模式之装饰器模式

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装.这种模式创建了一个装饰类,用来包装原 ...

  8. java设计模式之 装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装 ...

  9. Java单体应用 - 架构模式 - 03.设计模式-10.装饰器模式

    原文地址:http://www.work100.net/training/monolithic-architecture-design-patterns-decorator-pattern.html ...

最新文章

  1. SpringBoot+Junt+Mock测试方法
  2. Bdsyn百度手机助手是何物,它是怎样神不知鬼不觉地安装到你的电脑里的?
  3. Linux 目录配置标准:FHS
  4. 会c语言如何快速入门python,初学者如何从C语言到Python的转化(北大陈斌老师的举例 )...
  5. 190709每日一句 以这样的方式去过每一天,你的生活将永远改变!
  6. 【Labplus 3】Scratch获取角色造型的数量
  7. python从邻接矩阵计算可达矩阵,复制即用
  8. matlab图例只显示文字不显示线条
  9. 微信机器人之PC微信hook
  10. 逻辑回归算法及其实现
  11. oeasy教您玩转vim - 43 - # 替换模式
  12. Power Query零基础入门(Excel2021专业加强版)
  13. 计算机音乐超级马丽,你与你的音乐梦想,只差一台数学计算器
  14. CyanogenMod编译
  15. mysql教学版_MySQL 8从零开始学(视频教学版)
  16. 爱我所爱,行我所行,听从我心,无问西东
  17. C语言计算圆柱的表面积 体积
  18. Dropbox 架设免费个人网站
  19. c++小游戏大合集(1)
  20. 计算机导论实验课,《计算机导论》实验课教案

热门文章

  1. 计算机伦理期末题库2023 免费
  2. golang环境安装
  3. DOTA数据集 | retinanet 实验记录(COCO数据格式)
  4. 渗透测试:ASP/ASPX/JSP/JBoss攻防环境搭建
  5. java int 128 ==_Integer128==128?false,Integer和int使用==比较的总结
  6. list和dic区别
  7. 求助为什么这张图片只显示一条
  8. 长沙python培训机构培训
  9. SHELL中的exit 0 和 exit 1有什么区别?
  10. JavaScript自执行函数,自执行函数是什么,存在的意义?