Java设计模式 - 责任链模式
责任链模式应用场景:
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止.适合使用责任链模式的情景如下:有许多对象可以处理用户的请求,应用程序可以自动确定谁处理用户请求;希望在用户不必明确指定接收者的情况下,向多个接收者提交一个请求,程序希望动态定制可处理用户请求的对象集合.
源代码下载地址:
https://github.com/godlikecheng/Duty_Model/
责任链模式的实现方式:
(1)请求类Request:
package duty_model_01; /** * 请求类Request * @author 张宜成 */ public class Request { // 成员变量day代表请假的天数 int day; Request(int day) { this.day = day; } }
(2)抽象处理者类Handler
package duty_model_01; /** * 抽象处理者类Handler * @author 张宜成 */ public abstract class Handler { private Handler next; //定义后继处理者变量 public Handler getNext() { return next; } public void setNext(Handler next) { this.next = next; } public abstract boolean handle(Request req); // 定义抽象方法,子类要重写 }
(3)三个具体处理者类
package duty_model_01; /** * 三个具体处理者类 - 组长类 * @author 张宜成 */ public class ZuZhang extends Handler { static int limit = 1; public boolean handle(Request req) { if(req.day <= limit) { System.out.println("ZuZhang agree the request!"); return true; } return getNext().handle(req); } }
package duty_model_01; /** * 三个具体处理者类 * * @author 张宜成 */ public class ZhuRen extends Handler { static int limit = 2; public boolean handle(Request req) { if (req.day <= limit) { System.out.println("ZhuRen agrees the request !!"); return true; } return getNext().handle(req); } }
package duty_model_01; /** * 三个具体处理者类 -> 经理类 * * 组长 主任给员工假是有权限的,分别是1天和2天,因此在各自的handle()方法中是有if判断语句的; * 经理原则上可以批准 > 2 的任意假期期间,没有上限,因此在handle()方法中无if判断语句 * */ public class JingLi extends Handler { public boolean handle(Request req) { System.out.println("JingLi agree the request !!"); return true; } }
(4)生成责任链前后顺序关系
package duty_model_01; /** * 生成责任链前后顺序关系类 * * 从createChain()方法中可看出,责任链首节是组长对象,后继节点是主任对象,主任对象的后继节是经理对象. * handle()方法负责把请求Request对象req放入责任链首节点中并开始运行. * * @author 张宜成 */ public class MyChain { private Handler one = new ZuZhang(); private Handler two = new ZhuRen(); private Handler three = new JingLi(); public void createChain() { one.setNext(two); two.setNext(three); } public void handle(Request req) { one.handle(req); } }
(5)测试类
package duty_model_01; /** * 测试类 * @author 张宜成 */ public class Test { public static void main(String[] args) { Request req = new Request(2); // 定义请假1天的请求对象 MyChain mc = new MyChain(); mc.createChain(); //创建责任链 mc.handle(req); // 将请求放入链中 } }
运行结果:
反射的作用:
* 很明显.从编制的MyChain类可以看出:所形成的责任链是刚性的,若需求分析发生了变化,链中需增加
* 或者减少节点,我们必须重新修改MyChain类,以事应需求分析发展的需要,那么,能否不修改程序,而能又满足需求分析的
* 变化呢? 答案是可以的,那就是"配置文件 + 反射" 技术.
package duty_model_01; import java.io.FileInputStream; import java.util.Properties; /** * @author 张宜成 * */ public class MyChain2 { private Handler handle[]; public void createChain() { try { String path = this.getClass().getResource("/").getPath(); FileInputStream in = new FileInputStream(path + "one/myconfig.txt"); // 读取配置文件 Properties p = new Properties(); p.load(in); String s = p.getProperty("chain"); String unit[] = s.split(","); // 按","拆分,得各责任链类 int n = unit.length; handle = new Handler[n]; // 共有n个处理者 for(int i = 0; i < n; i ++) { // 通过反射技术加载各责任链类对象 handle[i] = (Handler)Class.forName(unit[i]).newInstance(); } for (int i = 0; i < n-1; i ++) { handle[i].setNext(handle[i + 1]); // 设置节点前后关系 } in.close(); }catch(Exception e) { e.printStackTrace(); } } public void handle(Request req) { handle[0].handle(req); } }
回调技术
案例: 对英文字符串数据进行如下功能处理:
(1) 全部变成大写字母; (2)去掉所有的空格
(1)请求类
package duty_model_02; /** * 测试类 * @author 张宜成 */ public class Test { public static void main(String[] args) { Request req = new Request("i am a student"); //请求对象 Response rep = new Response(""); // 响应对象 Filter one = new OneFilter(); // 定义过滤器1 Filter two = new TwoFilter(); // 定义过滤器2 FilterChain fc = new FilterChain(); //定义过滤器容器对象 fc.addFilter(one); //添加过滤器1对象 fc.addFilter(two); // 添加过滤器2对象 fc.doFilter(req, rep, fc); // 进行字符串级联过滤 System.out.println(rep.rep); // 输出字符串的过滤结果 } }
package duty_model_02; public class Response { String rep; Response(String rep) { this.rep = rep; } }
(2)FilterChain: * 该类主要包含两个功能: * 一是生成了过滤器集合对象; * 二是实现了回调功能
package duty_model_02; import java.util.ArrayList; /** * 该类主要包含两个功能: * 一是生成了过滤器集合对象; * 二是实现了回调功能 * @author 张宜成 */ public class FilterChain implements Filter { ArrayList<Filter> ary = new ArrayList(); int index = 0; void addFilter(Filter f) { ary.add(f); } public void doFilter(Request req, Response rep, FilterChain fc) { if(index == ary.size()) return; Filter f = ary.get(index); index ++; f.doFilter(req, rep, fc); } }
(3)定义抽象处理者接口Filter
package duty_model_02; /** * 接口类 - 由于本示例相当于过滤字符串功能,因此名称定义为Filter * Request代表请求类,包含对字符串的原生封装; * Response代表相应类,包含对处理后的结果字符串的封装; * FilterChain是过滤器容器类,其对象作为具体处理者必备的回调参数. * * * @author 张宜成 */ public interface Filter { void doFilter(Request req, Response rep, FilterChain fc); }
(4)具体处理者类
package duty_model_02; /** * 英文字符串大写转变为小写 */ public class OneFilter implements Filter { public void doFilter(Request req, Response rep, FilterChain fc) { String s = req.req; rep.rep = s.toUpperCase(); fc.doFilter(req, rep, fc); } }
package duty_model_02; /** * 去掉所有的空格类 * @author 张宜成 */ public class TwoFilter implements Filter { public void doFilter(Request req, Response rep, FilterChain fc) { String s = rep.rep; StringBuffer sbuf = new StringBuffer(); for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); if (ch != ' ') { sbuf.append(ch); } } rep.rep = sbuf.toString(); fc.doFilter(req, rep, fc); } }
测试类:
package duty_model_02; /** * 测试类 * @author 张宜成 */ public class Test { public static void main(String[] args) { Request req = new Request("i am a student"); //请求对象 Response rep = new Response(""); // 响应对象 Filter one = new OneFilter(); // 定义过滤器1 Filter two = new TwoFilter(); // 定义过滤器2 FilterChain fc = new FilterChain(); //定义过滤器容器对象 fc.addFilter(one); //添加过滤器1对象 fc.addFilter(two); // 添加过滤器2对象 fc.doFilter(req, rep, fc); // 进行字符串级联过滤 System.out.println(rep.rep); // 输出字符串的过滤结果 } }
运行结果:
从上述例子中FilterChain类的doFilter方法可以看出,它实现的其实是回调.若具体处理者花费时间很长,则应用程序就不能执行其他功能了.我们能否实现一种机制,再调用具体处理者执行时,调用者还能完成其他操作?毫无疑问,这要用到多线程技术,即利用多线程技术实现异步回调.
实现多线程技术实现异步回调,只需要将回调技术中的代码进行更改即可.
将上述的 -> FilterChain 更改:
package duty_model_02; import java.util.ArrayList; /** * 该类主要包含两个功能: * 一是生成了过滤器集合对象; * 二是实现了回调功能 * @author 张宜成 */ public class FilterChain implements Filter { ArrayList<Filter> ary = new ArrayList(); int index = 0; void addFilter(Filter f) { ary.add(f); } public void doFilter(Request req, Response rep, FilterChain fc) { if(index == ary.size()) return; Filter f = ary.get(index); index ++; // f.doFilter(req, rep, fc); MyThread th = new MyThread(req,rep,f,fc); th.start(); } }
将req rep f和fc进一步封装成线成MyThreadMyThread对象参数,启动线成实现了异步回调
package duty_model_02; /** * 将req rep f和fc进一步封装成线成MyThreadMyThread对象参数,启动线成实现了异步回调 * @author 张宜成 */ public class MyThread extends Thread { Request req; Response rep; Filter f; FilterChain fc; MyThread(Request req, Response rep, Filter f, FilterChain fc) { this.req = req; this.rep = rep; this.f = f; this.fc = fc; } public void run() { f.doFilter(req, rep, fc); } }