Java设计模式 - 责任链模式

😄 不断学习才是王道
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 一个有梦有戏的人 @怒放吧德德

拦截器

拦截器可以拦截目标方法,进行一系列的操作。也可以取代代理对象的方法等功能。以下代码用JDK动态代理来实现一个拦截器的逻辑。

1、接口提供

首先提供方法接口和实现类作为动态代理拦截的方法

1
2
3
4
5
6
7
8
9
10
package com.lyd.demo.service;

/**
* @Author: lyd
* @Description: 普通的接口
* @Date: 2022-08-19
*/
public interface HelloWorldService {
public void sayHelloWorld(String name);
}

实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.lyd.demo.service.impl;

import com.lyd.demo.service.HelloWorldService;

/**
* @Author: lyd
* @Description: 接口实现
* @Date: 2022-08-19
*/
public class HelloWorldServiceImpl implements HelloWorldService {
@Override
public void sayHelloWorld(String name) {
System.out.println("Hello World! " + name);
}
}

2、定义拦截器接口Interceptor

这里定义了三个方法:before、around、after,都有:代理对象 proxy, 真实对象 target, 方法 method, 参数 args

  • before方法返回的是Boolean,在真实对象前调用。
  • 返回true时,反射真实对象的方法,false时,调用around方法
    最后执行after方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.lyd.demo.interceptor;

import java.lang.reflect.Method;

/**
* @Author: lyd
* @Description: 拦截器接口
* @Date: 2022-08-17
*/
public interface Interceptor {
public boolean before(Object proxy, Object target, Method method, Object[] args);

public void around(Object proxy, Object target, Method method, Object[] args);

public void after(Object proxy, Object target, Method method, Object[] args);
}

3、定义拦截器实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.lyd.demo.impl;

import com.lyd.demo.interceptor.Interceptor;

import java.lang.reflect.Method;

/**
* @Author: lyd
* @Description: 实现拦截接口
* @Date: 2022-08-17
*/
public class MyInterceptor implements Interceptor {
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("反射方法前逻辑");
return false; // 不反射被代理对象原有方法
}

public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("取代了代理对象的方法");
}

public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("反射方法后逻辑");
}
}

4、采用JDK动态代理的方式使用拦截器

构建jdk代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.lyd.demo.jdk;

import com.lyd.demo.interceptor.Interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* @Author: lyd
* @Description: JDK动态代理使用拦截器
* @Date: 2022-08-17
*/
public class InterceptorJdkProxy implements InvocationHandler {

private Object target; // 真实对象
private String interceptorClass = null; // 拦截器全限定名

public InterceptorJdkProxy(Object target, String interceptorClass) {
this.target = target;
this.interceptorClass = interceptorClass;
}

/**
* 绑定委托对象并返回一个【代理占位】
* @param target 真实对象
* @return 代理对象
*/
public static Object bind(Object target, String interceptorClass) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InterceptorJdkProxy(target, interceptorClass));
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (interceptorClass == null) {
// 没有设置拦截器则直接反射原有方法
return method.invoke(proxy, args);
}
Object result = null;
// 通过反射生成拦截器
Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();
// 调用前置方法
if (interceptor.before(proxy, target, method, args)) {
//反射原有方法
return method.invoke(target, args);
} else { // 返回false方法执行around方法
interceptor.around(proxy, target, method, args);
}
// 调用后置方法
interceptor.after(proxy, target, method, args);
return result;
}
}

5、实例

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.lyd.demo.test;

import com.lyd.demo.jdk.InterceptorJdkProxy;
import com.lyd.demo.service.HelloWorldService;
import com.lyd.demo.service.impl.HelloWorldServiceImpl;

/**
* @Author: lyd
* @Description: 测试类
* @Date: 2022-08-19
*/
public class InterceptorTest {
public static void main(String[] args) {
HelloWorldService proxy = (HelloWorldService) InterceptorJdkProxy.bind(new HelloWorldServiceImpl(), "com.lyd.demo.impl.MyInterceptor");
proxy.sayHelloWorld("lyd");

}
}

结果:
结果1

责任链模式

当一个对象在一条链上被多个拦截器拦截处理,当然也可以不拦截处理,这种的设计模式就是责任链模式。可以在这被拦截的期间进行加工处理。就好比如,我们申请请假,需要经过项目经理,再到部门经理,最后到人事。在这期间,经理审批时候可以修改请假天数。本次实验用以上部分代码。

1、定义拦截器

这里定义三个拦截器分别是三个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.lyd.demo.impl;

import com.lyd.demo.interceptor.Interceptor;

import java.lang.reflect.Method;

/**
* @Author: lyd
* @Description: 责任链 - 拦截器1
* @Date: 2022-08-20
*/
public class Interceptor1 implements Interceptor {
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器1的before");
return true;
}

@Override
public void around(Object proxy, Object target, Method method, Object[] args) {

}

@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("拦截器1的after");
}
}

拦截器2,3也是如此就不粘贴代码了。

2、责任链上使用拦截器实例

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.lyd.demo.test;

import com.lyd.demo.jdk.InterceptorJdkProxy;
import com.lyd.demo.service.HelloWorldService;
import com.lyd.demo.service.impl.HelloWorldServiceImpl;

/**
* @Author: lyd
* @Description: 责任链模式测试
* @Date: 2022-08-20
*/
public class ResponsibilityChainTest {
public static void main(String[] args) {
HelloWorldService proxy1 = (HelloWorldService) InterceptorJdkProxy.bind(new HelloWorldServiceImpl(), "com.lyd.demo.impl.Interceptor1");

HelloWorldService proxy2 = (HelloWorldService) InterceptorJdkProxy.bind(proxy1, "com.lyd.demo.impl.Interceptor2");

HelloWorldService proxy3 = (HelloWorldService) InterceptorJdkProxy.bind(proxy2, "com.lyd.demo.impl.Interceptor3");

proxy3.sayHelloWorld("怒放吧德德");
}
}

运行结果:
结果2