Java设计模式(五)—— 责任链模式

        责任链模式定义如下:使多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止。

适合使用责任链模式的情景如下:

  • 有许多对象可以处理用户的请求,应用程序可自动确定谁处理用户请求
  • 希望在用户不必明确指定接受者的情况下,向多个接受者提交一个请求
  • 程序希望动态定制可处理用户请求的对象集合

一、问题的提出

        在生活中我们经常会遇到这样的问题,例如:在企业工作的员工请假问题。假设假期少于一天的可由组长决定;多余1天少于2天的,可由车间主任决定;大于2天的可由经理决定。 “组长——主任——经理”构成了一个功能链。员工提出请假请求后,组长根据权限决定是否同意员工请假。若超出其权限,则传递给下一个责任人——主任。主任根据权限决定是否同意请假,若超出权限,在传递给下一个责任人——经理

        也就是说,请假这个“请求”,一定可以在功能链中的某一节点处理并返回。

二、责任链设计模式

        由于是一系列类试图处理一个请求request,这些类之间是一个松散的耦合,唯一的共同点就是在他们之间传递请求request。

        也就是说,来了一个请求,A类先处理,如果没有处理,就传递到B类处理,如果没有处理,就传递给C类处理,这就像一个链条一样传递下去。

责任链模式涉及的角色如下:

  • 抽象处理者角色(Handler):定义一个处理请求的接口或抽象类。可定义一个方法,以设定和返回对下一节点的引用。
  • 具体处理者(ConcreteHandler):具体处理者接到请求后,可以选择将请求处理完毕,或者将请求传给下一节点。由于具体处理者持有对下一节点的引用,因此,如果需要,具体处理者可以访问下一节点。
  • 客户(Client):负责形成具体处理者的节点功能链,并传递初始请求。

利用责任链模式编制员工请假审批功能类:

 (1)请求类

public class Request {
    int day;  //请假的天数
    Request(int day) {
        this.day = day;
    }
}

(2)抽象处理者类Handler

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 request);
}

(3)三个具体处理者类

public class ZuZhang extends Handler{

    static int limit = 1;

    @Override
    public boolean handle(Request request) {
        if (request.day <= limit) {
            System.out.println("组长同意请假!");
            return true;
        }
        return getNext().handle(request);
    }
}
public class ZhuRen extends Handler{
    
    static int limit = 2;
    
    @Override
    public boolean handle(Request request) {
        if (request.day <= limit) {
            System.out.println("主任同意请假!");
            return true;
        }
        return getNext().handle(request);
    }
}
public class JingLi extends Handler{

    static int limit = 3;

    @Override
    public boolean handle(Request request) {
        if (request.day <= limit) {
            System.out.println("经理同意请假!");
            return true;
        }
        return getNext().handle(request);
    }
}

(4)生成责任链前后顺序关系类

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 request) {
        one.handle(request);
    }
}

(5)测试类

public class Test {
    public static void main(String[] args) {
        Request request = new Request(3);
        MyChain myChain = new MyChain();
        myChain.createChain();
        myChain.handle(request);
    }
}

测试结果:

经理同意请假!

三、反射的作用

        在上面的MyChain类可以看出:所形成的责任链是刚性的,若需求分析发生了变化,链中需增加或减少节点,我们必须重新修改MyChain类,以适应需求分析发展的需要。那么,能否不修改程序,而又能满足需求分析的变化呢?答案是可以的,那就是“配置文件+反射”技术。 

(1)对上面的例子而言,编写myconfig.txt配置文件:

chain=shejimoshi.zerenlian.ZuZhang,shejimoshi.zerenlian.ZhuRen,shejimoshi.zerenlian.JingLi

 放在了这个位置:

Java设计模式(五)—— 责任链模式_第1张图片

 (2)创建MyChain2

注释中很详细了写了每行代码的含义

import java.io.FileInputStream;
import java.util.Properties;

public class MyChain2 {
    //声明了一个私有成员变量 handle,用于存储责任链中的各个节点。
    private Handler handle[];
    public void createChain() {
        try {
            //这里打开了一个配置文件 myconfig.txt,并使用 Properties 类加载其中的配置信息。
            FileInputStream in = new FileInputStream("D:\\Java_Dev\\IDEA_Projects\\Personal_project\\programmer_code\\src\\main\\java\\shejimoshi\\zerenlian\\myconfig.txt");
            Properties properties = new Properties();
            properties.load(in);

            ///获取了配置文件中 chain 属性的值,并按照逗号分隔成一个字符串数组 unit,表示责任链中的节点。
            // 然后,代码通过数组的长度创建了一个 Handler 类型的数组 handle,用于存储责任链中的各个节点。
            String chain = properties.getProperty("chain");
            String unit[] = chain.split(",");
            int chainLength = unit.length;
            handle = new Handler[chainLength];
            //通使用Java反射机制,根据 unit 数组中的类名动态加载各个责任链节点对象,并存储到 handle 数组中。
            for (int i = 0; i < chainLength; i++) {
                handle[i] = (Handler) Class.forName(unit[i]).newInstance();
            }
            //通过遍历 handle 数组,设置责任链节点之间的前后关系。
            for (int i = 0; i < chainLength - 1; i++) {
                handle[i].setNext(handle[i+1]);
            }
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //这个方法是责任链模式的核心,用于处理请求。这里直接调用责任链中的第一个节点来处理请求。
    public void handle(Request request) {
        handle[0].handle(request);
    }
}

(3)再次测试

public class Test {
    public static void main(String[] args) {
        Request request = new Request(2);
        MyChain2 myChain = new MyChain2();
        myChain.createChain();
        myChain.handle(request);
    }
}

测试结果:

主任同意请假!

(4)新增责任链

增加一个董事长的处理者,经理不能处理的时候转交给董事长处理

public class DongShiZhang extends Handler{

    static int limit = 5;

    @Override
    public boolean handle(Request request) {
        if (request.day <= limit) {
            System.out.println("董事长同意请假!");
            return true;
        }
        return getNext().handle(request);
    }
}

(5)修改配置文件

增加董事长

chain=shejimoshi.zerenlian.ZuZhang,shejimoshi.zerenlian.ZhuRen,shejimoshi.zerenlian.JingLi,shejimoshi.zerenlian.DongShiZhang

(5)再次测试

public class Test {
    public static void main(String[] args) {
        Request request = new Request(4);
        MyChain2 myChain = new MyChain2();
        myChain.createChain();
        myChain.handle(request);
    }
}

测试结果:

董事长同意请假!

        总结:可以看到,当需求发生变化时,只需要增加责任链中的具体处理者类,然后在配置文件中添加该具体处理者,并不需要去修改MyChain2的内容,这就是反射的作用。

你可能感兴趣的:(设计模式,设计模式,责任链模式,servlet)