Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合,唯一共同点是在他们之间传递request. 也就是说,来了一个请求,A类先处理,如果没有处理,就传递到B类处理,如果没有处理,就传递到C类处理,就这样象一个链条(chain)一样传递下去。
(1)AOP
(2)Servlet filter
在一个链上,都有相应职责的类,因此叫Chain of Responsibility.
优点:
因为无法预知来自外界(客户端)的请求是属于哪种类型,每个类如果碰到它不能处理的请求只要放弃就可以。
缺点:
(1)效率低,因为一个请求的完成可能要遍历到最后才可能完成,当然也可以用树的概念优化。 在Java AWT1.0中,对于鼠标按键事情的处理就是使用CoR,到Java.1.1以后,就使用Observer代替CoR
(2)扩展性差,因为在CoR中,一定要有一个统一的接口Handler.局限性就在这里。
与Command模式区别:
Command 模式需要事先协商客户端和服务器端的调用关系,比如 1 代表 start ,2 代表 move 等,这些 都是封装在 request 中,到达服务器端再分解。
CoR 模式就无需这种事先约定,服务器端可以使用 CoR 模式进行客户端请求的猜测,一个个猜测 试验。
aop chain
handler
public abstract class Handler { /** * @link aggregation * @supplierCardinality 0..1 */ protected Handler successor; public abstract void handleRequest(); public void setSuccessor(Handler successor) { this.successor = successor; } public Handler getSuccessor() { return successor; } }
handler实现类
public class ConcreteHandler extends Handler { public void handleRequest() { if (getSuccessor() != null) { System.out.println("The request is passed to " + getSuccessor()); getSuccessor().handleRequest(); } else { System.out.println("The request is handled here."); } } }
客户端
public class Client { /** * @directed */ static private Handler handler1, handler2; public static void main(String[] args) { handler1 = new ConcreteHandler(); handler2 = new ConcreteHandler(); handler1.setSuccessor(handler2); handler1.handleRequest(); } }
(2)抽象出Request
handler接口
public interface Handler{ public void handleRequest(Request request); }
request类
public class Request{ private String type; public Request(String type){this.type=type;} public String getType(){return type;} public void execute(){ //request真正具体行为代码 } }
handler实现
public class ConcreteHandler implements Handler{ private Handler successor; public ConcreteHandler(Handler successor){ this.successor=successor; } public void handleRequest(Request request){ if (request instanceof HelpRequest){ //这里是处理Help的具体代码 }else if (request instanceof PrintRequst){ request.execute(); }else //传递到下一个 successor.handle(request); } } }
filter实例
/** * 整个web的编码过滤 * 设定为UTF-8编码 * @author: caibosi * @created: 2013-10-20 * @time: 15:18:12 */ //@WebFilter(value="/*",asyncSupported = true) public class EncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); } @Override public void destroy() { } }
具体看tomcat的ApplicationFilterChain的实现
aop chain
/** * @author caibosi * @created 2013-10-30 */ public class AopChain { /** * 对一个方法的一系列拦截 */ private List<AopFilter> aopList; /** * 当前拦截的index */ private int currentAopIndex = 0; /** * 被拦截的类 */ private Class<?> targetClass; /** * 被拦截的对象 */ private Object targetObject; /** * 被拦截的方法 */ private Method targetMethod; /** * 被拦截的方法的参数 */ private Object[] methodParams; /** * 经过拦截处理后的方法 */ private MethodProxy aoppedMethod; /** * 被拦截处理后的对象 */ private Object aoppedObject; public AopChain(Class<?> targetClass,Object targetObject,Method targetMethod, Object[] methodParams,MethodProxy methodProxy,List<AopFilter> aopList){ this.targetClass = targetClass; this.targetObject = targetObject; this.targetMethod = targetMethod; this.aoppedMethod = methodProxy; this.methodParams = methodParams; this.aopList = aopList; } /** * 执行当前拦截 * 并挑战到下一个拦截 */ public void executeAndNext(){ if(currentAopIndex < aopList.size()){ AopFilter aop = aopList.get(currentAopIndex); //设置下一个拦截 currentAopIndex++; //执行当前拦截,传入chain,拦截后继续调用chain的executeAndNext aop.execute(this); } else{ try { aoppedObject = aoppedMethod.invokeSuper(targetObject,methodParams); } catch (Throwable throwable) { ExceptionTool.transformException(throwable); } } } public Class<?> getTargetClass() { return targetClass; } public Object getTargetObject() { return targetObject; } public Method getTargetMethod() { return targetMethod; } public Object[] getMethodParams() { return methodParams; } public MethodProxy getAoppedMethod() { return aoppedMethod; } public Object getAoppedObject() { return aoppedObject; } }
aop filter类
/** * @author: caibosi * @created: 2013-10-31 */ public abstract class AopFilter { //aop的拦截方法 public void execute(AopChain chain) { Class<?> targetClass = chain.getTargetClass(); Method targetMethod = chain.getTargetMethod(); Object[] params = chain.getMethodParams(); //调用模板,提供钩子方法 begin(targetClass,targetMethod,params); try{ if(filter(targetClass,targetMethod,params)){ before(targetClass,targetMethod,params); chain.executeAndNext(); after(targetClass,targetMethod,params); }else{ chain.executeAndNext(); } } catch (Exception e){ /** * 这里catch exception,而不是throwable * http://www.importnew.com/7383.html * http://docs.oracle.com/javase/7/docs/api/ * * error和exception都继承至throwalbe接口 * 而error属于jvm系统的异常,一般无法控制 * Error表示编译时和系统错误,通常不能预期和恢复,比如硬件故障、JVM崩溃、内存不足等 * 因而这里不捕获,而捕获exception * * exception又分runtime exception 和checked exception * checked exception 一般跟外部资源有关(如文件、数据库等) * 自定义的exception继承至runtime exception * * throws用在方法头,用来标记该方法可能没有处理的异常,需要调用者警惕 * throw * */ error(targetClass,targetMethod,params,e); } finally { end(targetClass,targetMethod,params); } } //钩子方法,可以延迟到子类实现 public void begin(Class<?> targetClass,Method targetMethod,Object[] params){} public void end(Class<?> targetClass,Method targetMethod,Object[] params){} public boolean filter(Class<?> targetClass,Method targetMethod,Object[] params){ return true; } public void before(Class<?> targetClass, Method targetMethod, Object[] params) {} public void after(Class<?> targetClass, Method targetMethod, Object[] params) {} public void error(Class<?> targetClass, Method targetMethod, Object[] params, Exception e){} }
aop factory
/** * @author caibosi * @created 2013-10-30 */ public class AopFactory { public static <T> T getAoppedObject(final Class<?> targetClass,final List<AopFilter> aopList){ return (T) Enhancer.create(targetClass,new MethodInterceptor() { @Override public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { AopChain aopChain = new AopChain(targetClass,target,method,args,methodProxy,aopList); aopChain.executeAndNext(); return aopChain.getAoppedObject(); } }); } }