假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击http://106.12.206.16:8080/qingruihappy/index.html
谷歌
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
介绍
意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
何时使用:在处理消息的时候以过滤很多道。
如何解决:拦截的类都实现统一接口。
关键代码:Handler 里面聚合它自己,在 HanleRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
应用实例: 1、红楼梦中的"击鼓传花"。 2、JS 中的事件冒泡。 3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。
优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。
使用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。
注意事项:在 JAVA WEB 中遇到很多应用。
一,一个初步的责任链模式的拦截器
拦截器接口
package com.DesignPatterns.an.Responsibility1; public interface Filter { String doFilter(String str); }
拦截器实现
package com.DesignPatterns.an.Responsibility1; public class HTMLFilter implements Filter { @Override public String doFilter(String str) { //process the html tag <> String r = str.replace('<', '[') .replace('>', ']'); return r; } }
package com.DesignPatterns.an.Responsibility1; public class SesitiveFilter implements Filter { @Override public String doFilter(String str) { String r = str.replace("被就业", "就业") .replace("敏感", ""); return r; } }
package com.DesignPatterns.an.Responsibility1; public class FaceFilter implements Filter { @Override public String doFilter(String str) { return str.replace(":)", "^V^"); } }
拦截器代码
package com.DesignPatterns.an.Responsibility1; public class MsgProcessor { private String msg; Filter[] filters = {new HTMLFilter(), new SesitiveFilter(), new FaceFilter()}; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String process() { String r=msg; for(Filter f:filters) { f.doFilter(r); } return r; } }
package com.DesignPatterns.an.Responsibility1; /** * 这个是责任链设计模式(拦截器设计模式)的入门 * @author qingruihappy * @data 2018年11月5日 下午11:48:05 * @说明:主要设计思路就是让所有的拦截器都实现同样的接口,让后把所有的拦截器都放在一个list集合中来。 * 假如在加一个拦截器的话就会拦截器的process方法是不用变的,只需要在Filter[] filters的数组中把已经实现了 * Filter接口的实现类加进来就行了。 * * 但是现在假如我们在拦截器的中间在加一组拦截器怎么办呢? */ public class Main { /** * @param args */ public static void main(String[] args) { String msg = "大家好:),<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿"; MsgProcessor mp = new MsgProcessor(); mp.setMsg(msg); String result = mp.process(); System.out.println(result); } }
大家好^V^,[script],,就业,网络授课没感觉,因为看不见大家伙儿
二,平常我们看到的责任链的开发
package com.DesignPatterns.an.Responsibility2; public interface Filter { String doFilter(String str); }
package com.DesignPatterns.an.Responsibility2; public class HTMLFilter implements Filter { @Override public String doFilter(String str) { //process the html tag <> String r = str.replace('<', '[') .replace('>', ']'); return r; } }
package com.DesignPatterns.an.Responsibility2; public class SesitiveFilter implements Filter { @Override public String doFilter(String str) { //process the sensitive words String r = str.replace("被就业", "就业") .replace("敏感", ""); return r; } }
package com.DesignPatterns.an.Responsibility2; public class FaceFilter implements Filter { @Override public String doFilter(String str) { return str.replace(":)", "^V^"); } }
责任链模式的工具类
package com.DesignPatterns.an.Responsibility2; import java.util.ArrayList; import java.util.List; /** * * @author qingruihappy * @data 2018年11月6日 上午12:10:42 * @说明:这个类主要是用来添加过滤器及其便利过滤器的 */ public class FilterChain { List<Filter> filters = new ArrayList<Filter>(); /*注意这里的用法,我们返回的是类本身,这样我们就可以用fc.addFilter(new HTMLFilter()) .addFilter(new SesitiveFilter())这种责任链的编码方式了。 ;*/ public FilterChain addFilter(Filter f) { this.filters.add(f); return this; } public String doFilter(String str) { String r = str; for(Filter f: filters) { r = f.doFilter(r); } return r; } }
package com.DesignPatterns.an.Responsibility2; /** * 这个类主要是用来调用FilterChain的 * @author qingruihappy * @data 2018年11月6日 上午12:11:34 * @说明: */ public class MsgProcessor { private String msg; FilterChain fc; public FilterChain getFc() { return fc; } public void setFc(FilterChain fc) { this.fc = fc; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String process() { return fc.doFilter(msg); } }
package com.DesignPatterns.an.Responsibility2; public class Main { /** * @param args */ public static void main(String[] args) { String msg = "大家好:),<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿"; MsgProcessor mp = new MsgProcessor(); mp.setMsg(msg); FilterChain fc = new FilterChain(); fc.addFilter(new HTMLFilter()) .addFilter(new SesitiveFilter()) .addFilter(new FaceFilter()); mp.setFc(fc); String result = mp.process(); System.out.println(result); } }
大家好^V^,[script],,就业,网络授课没感觉,因为看不见大家伙儿
三,在一组责任链中加入另一组责任链
package com.DesignPatterns.an.Responsibility3; public interface Filter { String doFilter(String str); }
package com.DesignPatterns.an.Responsibility3; public class HTMLFilter implements Filter { @Override public String doFilter(String str) { //process the html tag <> String r = str.replace('<', '[') .replace('>', ']'); return r; } }
package com.DesignPatterns.an.Responsibility3; public class SesitiveFilter implements Filter { @Override public String doFilter(String str) { //process the sensitive words String r = str.replace("被就业", "就业") .replace("敏感", ""); return r; } }
package com.DesignPatterns.an.Responsibility3; public class FaceFilter implements Filter { @Override public String doFilter(String str) { return str.replace(":)", "^V^"); } }
package com.DesignPatterns.an.Responsibility3; import java.util.ArrayList; import java.util.List; public class FilterChain implements Filter { List<Filter> filters = new ArrayList<Filter>(); /*注意这里的用法,我们返回的是类本身,这样我们就可以用fc.addFilter(new HTMLFilter()) .addFilter(new SesitiveFilter())这种责任链的编码方式了。 ;*/ public FilterChain addFilter(Filter f) { this.filters.add(f); return this; } public String doFilter(String str) { String r = str; for(Filter f: filters) { r = f.doFilter(r); } return r; } }
package com.DesignPatterns.an.Responsibility3; public class MsgProcessor { private String msg; FilterChain fc; public FilterChain getFc() { return fc; } public void setFc(FilterChain fc) { this.fc = fc; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String process() { return fc.doFilter(msg); } }
package com.DesignPatterns.an.Responsibility3; /** * 这里主要注意的是在一组拦截器中加入另一组拦截器的 * @author qingruihappy * @data 2018年11月6日 上午12:15:36 * @说明: */ public class Main { /** * @param args */ public static void main(String[] args) { String msg = "大家好:),<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿"; MsgProcessor mp = new MsgProcessor(); mp.setMsg(msg); FilterChain fc = new FilterChain(); fc.addFilter(new HTMLFilter()) .addFilter(new SesitiveFilter()) ; //注意在这里让FilterChain也去实现Filter接口,它按照黑盒的思路来看的话其实就是 //另一个数组,直接在原来的数组中加入另一个数组就行了。看下面的实现。 FilterChain fc2 = new FilterChain(); fc2.addFilter(new FaceFilter()); fc.addFilter(fc2); mp.setFc(fc); String result = mp.process(); System.out.println(result); } }
四,请求责任链拦截,返回责任链拦截,并且是先进后出的堆栈模式
package com.DesignPatterns.an.Responsibility4; public class Request { String requestStr; public String getRequestStr() { return requestStr; } public void setRequestStr(String requestStr) { this.requestStr = requestStr; } }
package com.DesignPatterns.an.Responsibility4; public class Response { String responseStr; public String getResponseStr() { return responseStr; } public void setResponseStr(String responseStr) { this.responseStr = responseStr; } }
package com.DesignPatterns.an.Responsibility4; public interface Filter { void doFilter(Request request, Response response, FilterChain chain); }
package com.DesignPatterns.an.Responsibility4; public class HTMLFilter implements Filter { @Override public void doFilter(Request request, Response response, FilterChain chain) { //process the html tag <> request.requestStr = request.requestStr.replace('<', '[') .replace('>', ']') + "---HTMLFilter()"; chain.doFilter(request, response, chain); response.responseStr += "---HTMLFilter()"; } }
package com.DesignPatterns.an.Responsibility4; public class SesitiveFilter implements Filter { @Override public void doFilter(Request request, Response response, FilterChain chain) { request.requestStr = request.requestStr.replace("被就业", "就业") .replace("敏感", "") + "---SesitiveFilter()"; chain.doFilter(request, response, chain); response.responseStr += "---SesitiveFilter()"; } }
package com.DesignPatterns.an.Responsibility4; import java.util.ArrayList; import java.util.List; public class FilterChain implements Filter { List<Filter> filters = new ArrayList<Filter>(); int index = 0; public FilterChain addFilter(Filter f) { this.filters.add(f); return this; } @Override public void doFilter(Request request, Response response, FilterChain chain) { if(index == filters.size()) return ; Filter f = filters.get(index); index ++; f.doFilter(request, response, chain); } }
package com.DesignPatterns.an.Responsibility4; /** * * @author qingruihappy * @data 2018年11月6日 上午12:23:38 * @说明:这个主要处理的就是有请求有返回的,而且要遵循先进后出的逻辑堆栈的逻辑 * 这里主要用到了递归的方法。其实也简单 * 我们来写一下它的思路 * 1:我们先把HTMLFilter,SesitiveFilter两个过滤器加载到过滤器链中。 * 2:调用FilterChain的doFilter方法,我们初始化index的索引是0,这个时候index++之后就会变成1,而现在我们get(0)的时候就会获取到 * HTMLFilter的doFilter方法,执行HTMLFilter里面的替换的方法。 * 3,当在HTMLFilter执行完之后会执行FilterChain里面的doFilter的方法,因为这个时候index是1了,这个时候会把index++后设置成2,让后执行 * SesitiveFilter里面的doFilter方法,在执行完SesitiveFilter里面的替换的方法之后。 * 4,接着调用FilterChain里面的doFilter的方法,这个时候发现index是2了就会返回 * 5,首先它会遵循方法堆栈中的先进后出的原则,回到SesitiveFilter类中执行response的相关代码 * 6,然后在回到HTMLFilter类中执行response的方法 */ public class Main { /** * @param args */ public static void main(String[] args) { String msg = "大家好:),<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿"; Request request = new Request(); request.setRequestStr(msg); Response response = new Response(); response.setResponseStr("response"); FilterChain fc = new FilterChain(); fc.addFilter(new HTMLFilter()) .addFilter(new SesitiveFilter()) ; fc.doFilter(request, response, fc); System.out.println(request.getRequestStr()); System.out.println(response.getResponseStr()); } }
大家好:),[script],,就业,网络授课没感觉,因为看不见大家伙儿---HTMLFilter()---SesitiveFilter()
response---SesitiveFilter()---HTMLFilter()
五,servlet过滤器的一览
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { /* 在访问的时候执行 */ System.out.println("======= 开始执行doFilter ========"); // 转发到下一个组件,进行后续的处理(组件可以是一个过滤器,也可以是一个servlet) chain.doFilter(request, response); System.out.println("======= 结束执行doFilter ========"); }
是不是很像啊,假如有多个过滤器的话那么我们就在xml文件中进行多个配置
如下面的。
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class BasicsFilter implements Filter { public BasicsFilter() { // 容器(服务器)启动时执行 } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { /* 容器(服务器)时执行 */ System.out.println("======== 初始化方法 ========"); // 获取的是web.xml中配置Filter时设置的值,参数为设置值得名称,若参数不存在,则返回空 String initParam = fConfig.getInitParameter("param"); System.out.println("param ========" + initParam); } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { /* 在访问的时候执行 */ System.out.println("======= 开始执行doFilter ========"); // 转发到下一个组件,进行后续的处理(组件可以是一个过滤器,也可以是一个servlet) chain.doFilter(request, response); System.out.println("======= 结束执行doFilter ========"); } /** * @see Filter#destroy() */ public void destroy() { // TODO Auto-generated method stub } }
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class otherFilter implements Filter { public otherFilter() { // 容器(服务器)启动时执行 } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { /* 容器(服务器)时执行 */ System.out.println("======== 初始化方法 ========"); // 获取的是web.xml中配置Filter时设置的值,参数为设置值得名称,若参数不存在,则返回空 String initParam = fConfig.getInitParameter("param"); System.out.println("param ========" + initParam); } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { /* 在访问的时候执行 */ System.out.println("======= 开始执行doFilter ========"); // 转发到下一个组件,进行后续的处理(组件可以是一个过滤器,也可以是一个servlet) chain.doFilter(request, response); System.out.println("======= 结束执行doFilter ========"); } /** * @see Filter#destroy() */ public void destroy() { // TODO Auto-generated method stub } }
在下面的xml中有两个拦截器,它是按照在xml中的顺序执行的。从这里我们不难看出,谁在前面就会先通过xml的解析jar包把谁加载到list或者数组中来,这样的话就会先执行谁,是不是和我们上面4的案例很像呢。
<filter> <filter-name>basicsFilter</filter-name> <filter-class>com.hudongwu.filter.BasicsFilter</filter-class> <init-param><!-- 设置在过滤器中执行初始化方法时,获取的值 --> <param-name>param</param-name> <param-value>studyFilter</param-value> </init-param> </filter> <filter> <filter-name>otherFilter</filter-name> <filter-class>com.hudongwu.filter.otherFilter</filter-class> <init-param><!-- 设置在过滤器中执行初始化方法时,获取的值 --> <param-name>param</param-name> <param-value>otherFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>basicsFilter</filter-name> <!-- 设置为访问该网站所有地址都需要通过该过滤器 --> <url-pattern>/*</url-pattern> <!-- 设置为只有访问该网站的/Helloword地址时才通过该过滤器 --> <url-pattern>/Helloword</url-pattern> </filter-mapping> <filter-mapping> <filter-name>otherFilter</filter-name> <!-- 设置为访问该网站所有地址都需要通过该过滤器 --> <url-pattern>/*</url-pattern> <!-- 设置为只有访问该网站的/otherFilter地址时才通过该过滤器 --> <url-pattern>/otherFilter</url-pattern> </filter-mapping>
假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击http://106.12.206.16:8080/qingruihappy/index.html
ll