- 责任链模式的应用场景
上一篇我们说到设计者一般会用拦截器来代替动态代理, 然后将拦截器的接口提供给开发者, 从而简化开发难度, 但是拦截器可能有多个。举个例子, 一个员工需要请假一周。如果把请假申请单看成一个对象, 那么它需要经过项目经理, 部门经理, 人事等多个角色的审批, 每个角色都有机会通过拦截这个申请单进行批阅和修改。此时的这三个部门就相当于三个拦截器, 而请假申请单则代表用户的请求。
当一个对象在一条链上被多个拦截器处理(拦截器来决定是否拦截)时, 这样的设计模式称为拦截器模式, 主要应用在一个对象在多个角色中传递的场景。
- 责任链模式的实现方法
了解了责任链模式后, 我们来看看如何构建一个责任链。还是以刚才的栗子为例, 申请单走到项目经理, 项目经理可能把时间从'两周'改为'三周', 从而影响后面的审批, 后面的审批度需要根据前面的结果来进行。这个时候可以考虑使用层层代理来实现。当申请单走到项目经理处, 生成第一个动态代理proxy1, 当它走到部门经理处, 在proxy1的基础上生成proxy2, 同理当申请单走到人事后, 在proxy的基础上生成proxy3。实际情况中可能还会有更多的部门, 以此类推即可。
- 代码实现
项目包结构如下
目标对象类
Leave.java
package chain;
public class Leave implements Say {
@Override
public void sayHello(String name) {
System.out.println("请假: " + name);
}
}
由于是基于jdk的动态代理所以需要实现一个接口类。
Say.java
package chain;
public interface Say {
void sayHello(String hello);
}
新建拦截器接口。
Interceptor.java
package chain;
import java.lang.reflect.Method;
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);
}
新建拦截类, 实现具体的拦截逻辑。
Interceptor1.java
package chain;
import java.lang.reflect.Method;
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 方法");
}
}
Interceptor2.java
package chain;
import java.lang.reflect.Method;
public class Interceptor2 implements Interceptor {
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("[拦截器2] 的 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("[拦截器2] 的 after 方法");
}
}
Interceptor3.java
package chain;import java.lang.reflect.Method;public class Interceptor3 implements Interceptor {
@Override public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("[拦截器3] 的 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("[拦截器3] 的 after 方法"); }
}
新建代理类, 实现代理逻辑
InterceptorJdkProxy.java
package chain;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
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 真实对象
* @param interceptorClass 拦截器类全路径名
* @return 代理对象
*/
public static Object bind(Object target, String interceptorClass)
{
// 取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InterceptorJdkProxy(target, interceptorClass));
}
/**
* 通过代理对象进入方法, 首先进入这个方法
*
* @param proxy 代理对象
* @param method 方法, 真实对象被调用的方法
* @param args 方法的参数
* @throws Throwable 异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (interceptorClass == null) {
return method.invoke(target, args);
}
Object result = null;
// 通过反射生成拦截器
Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();
// 调用前置方法
if (interceptor.before(proxy, target, method, args)) {
// 反射原有对象方法
result = method.invoke(target, args);
} else { // 返回 false 执行 around 方法
interceptor.around(proxy, target, method, args);
}
// 调用后置方法
interceptor.after(proxy, target, method, args);
return result;
}
}
新建测试类
Test.java
package chain;
public class Test {
public static void main(String[] args)
{
Say proxy1 = (Say) InterceptorJdkProxy.bind(new Leave(), "chain.Interceptor1");
Say proxy2 = (Say) InterceptorJdkProxy.bind(proxy1, "chain.Interceptor2");
Say proxy3 = (Say) InterceptorJdkProxy.bind(proxy2, "chain.Interceptor3");
proxy3.sayHello("一周");
}
}
- 运行结果
before 方法会按照从最后一个拦截器到第一个拦截器的顺序运行, 而 after 方法则按照从第一个拦截器到最后一个拦截器的顺序运行。责任链模式的优点在于我们可以在传递链上加入新的逻辑, 程序的扩展性高, 但缺点是会增加代理和反射, 使程序性能下降。