likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 14

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

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;
    }
    
    @Override
    public void operation() {
        component.operation(); // 调用被装饰者对象的方法
    }
}

// 具体装饰器类A
public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }
    
    @Override
    public void operation() {
        super.operation(); // 调用父类的方法
        System.out.println("为具体组件A增加额外功能");
    }
}

// 具体装饰器类B
public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }
    
    @Override
    public 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);
    }

    @Override
    public 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);
    }

    @Override
    public 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);
    }

    @Override
    public 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字段中。

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

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