问题提出
在生活中,经常遇到这样的问题。例如:在企业中,员工请假的问题。假设假期少于一天,可由组长决定;少于两天的,可由车间主任决定;大于两天的,由经理决定。组长、主任、经理构成了一条功能链。员工逐级向上进行申请,直到获得授权。再比如生产产品,需要经过多道工序。
解决以上这些问题,责任链模式是一个较好的选择。
责任链模式
责任链模式的定义如下:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
适用的情景如下:
- 有许多对象可以处理用户的请求,应用程序可以自动确定谁处理用户请求。
- 希望用户在不必明确指定接收者的情况下,向多个接收者提交一个请求,
- 程序希望动态定制可处理用户请求的对象集合。
责任链模式中涉及的角色如下:
- 抽象处理者(Handler):定义一个处理请求的抽象类。可以定义一个方法,以设定和返回下一个节点的引用。
- 具体处理者(ConcreteHandler):具体处理者在接收到请求之后可以选择将请求处理完毕,或者将请求传递给下一个节点。
- 客户(Client):负责形成具体处理者的功能链,并传递初始的请求。
简单实现
请求类,day为请假的天数。
public class Request {
public int day;
public Request(int day) {
this.day = day;
}
}
抽象处理者类
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);
}
三个具体的处理者类,组长
public class ZuZhang extends Handler{
static int limit = 1;
@Override
public boolean handle(Request req) {
if (req.day <= limit){
System.out.println("ZuZhang agree the request!");
return true;
}
return getNext().handle(req);
}
}
主任
public class ZhuRen extends Handler {
static int limit = 2;
@Override
public boolean handle(Request req) {
if (req.day <= limit){
System.out.println("ZhuRen agree the request!");
return true;
}
return getNext().handle(req);
}
}
经理
public class JingLi extends Handler{
@Override
public boolean handle(Request req) {
System.out.println("JingLi agree the request!");
return true;
}
}
客户类,生成责任链的前后顺序关系。
public class Chain {
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);
}
}
简单测试类
public class Test {
public static void main(String[] args) {
Request req = new Request(2);
Chain c = new Chain();
c.createChain();
c.handle(req);
}
}
加入反射
上述代码中,Chain构建的责任链是刚性的,若需求发生了变化,链中需增加或删除节点。解决这个问题,可采取配置文件+反射的方式。
定义config.properties中的格式为:
chain=ZuZhang,ZhuRen,JingLi
Chain2
public class Chain2 {
private Handler handler[];
public void createChain() {
try {
String path = "路径\\config.properties";
FileInputStream in = new FileInputStream(path);
Properties p = new Properties();
p.load(in);
String s = p.getProperty("chain");
String unit[] = s.split(",");
int n = unit.length;
handler = new Handler[n];
for (int i = 0; i < n; i++) {
handler[i] = (Handler) Class.forName(unit[i]).newInstance();
}
for (int i = 0; i < n - 1; i++) {
handler[i].setNext(handler[i + 1]);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void handle(Request req) {
handler[0].handle(req);
}
}
回调技术
回调就是类对象方法间相互调用的技术。例如:
public class A {
public void fA(){
System.out.println("This is A::fA()");
B obj = new B();
obj.fB(this);
}
public void fA2(){
System.out.println("This is A::fA2()");
}
public static void main(String[] args) {
new A().fA();
}
}
public class B {
public void fB(A obj){
System.out.println("This is B::fB()");
obj.fA2();
}
}
利用回调技术,也可以实现责任链模式的功能代码。
应用示例
对英文字符串数据进行如下处理:
- 全部变为大写字母
- 去掉所有空格
例如“I am a student”,经处理后变为“IAMASTUDENT”。代码如下:
定义抽象处理者接口Filter
public interface Filter {
void doFilter(Request req, Response rep,FilterChain fc);
}
请求类
public class Request {
String req;
public Request(String req) {
this.req = req;
}
}
响应类
public class Response {
String rep;
public Response(String rep) {
this.rep = rep;
}
}
两个具体处理类,小写变大写
public class UpperFilter implements Filter {
@Override
public void doFilter(Request req, Response rep, FilterChain fc) {
String s = req.req;
rep.rep = s.toUpperCase();
fc.doFilter(req, rep, fc);
}
}
去除空格
public class BlankFilter implements Filter {
@Override
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);
}
}
实现回调功能,生成过滤集合。
public class FilterChain implements Filter {
ArrayList<Filter> ary = new ArrayList<>();
int index = 0;
void addFilter(Filter f) {
ary.add(f);
}
@Override
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);
}
}
测试类
public class Test {
public static void main(String[] args) {
Request req = new Request("i am a student");
Response rep = new Response("");
Filter upperFilter = new UpperFilter();
Filter blankFilter = new BlankFilter();
FilterChain fc = new FilterChain();
fc.addFilter(upperFilter);
fc.addFilter(blankFilter);
fc.doFilter(req, rep, fc);
System.out.println(rep.rep);
}
}
上述代码doFilter方法的实现是同步的,若请求处理时间很长,则程序无法执行其他功能。
异步调用
可采用多线程技术实现异步调用。
FilterChain实现异步回调
public class FilterChain {
ArrayList<Filter> ary = new ArrayList<>();
int index = 0;
public 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++;
MyThread th = new MyThread(req,rep,f,fc);
th.start();
}
}
封装req、rep、f、fc
public class MyThread extends Thread {
Request req;
Response rep;
Filter f;
FilterChain fc;
public MyThread(Request req, Response rep, Filter f, FilterChain fc) {
this.req = req;
this.rep = rep;
this.f = f;
this.fc = fc;
}
@Override
public void run() {
f.doFilter(req, rep, fc);
}
}