【行为型模式】责任链模式,Java实现

【行为型模式】责任链模式,Java实现

前言

设计模式作业:

某 OA 系统需要提供一个假条审批的模块,如果员工请假天数小于3天,主任可以审批该假条;如果员工请假天数大于等于3天,小于10天,经理可以审批;如果员工请假天数大于等于10天,小于30天,总经理可以审批;如果超过30天,总经理也不能审批,提示相应的拒绝信息。

从这个作业要求,简单分析出:一个请假条有多个对象(主任、经理、总经理)来处理,但具体由哪个对象来处理,根据条件判断(请假天数)来确定,如果不能处理会传递给该链中的下一个对象,直到有对象处理它为止。这符合责任链模式的要求,所以可以使用责任链模式来完成此次作业。

一、责任链模式起步

责任链模式也称职责链模式。为了避免请求发送者与多个处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

1. 角色及作用

  • 抽象处理者角色:定义一个处理请求的接口,包含抽象处理和一个后继连接;
  • 具体处理者角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理则对本次请求进行处理,否则将该请求传给它的后继处理者;
  • 客户类角色:创建处理链,并向链头的具体处理者对象提交请求,它并不关心处理细节和请求的传递过程。

2. UML关系图

在这里插入图片描述

关键: Handler 里面聚合它自己,在 HandleRequest() 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。

二、代码实现

  • 首先将请求任务封装为一个类LeaveRequest,通过构造函数传入请假员工的姓名以及请假的天数,代码如下:
public class LeaveRequest {

    private String leaveName;

    private int leaveDays;

    public LeaveRequest(String leaveName, int leaveDays) {
        this.leaveName = leaveName;
        this.leaveDays = leaveDays;
    }

    public String getName() {
        return leaveName;
    }

    public int getLeaveDays() {
        return leaveDays;
    }
}
  • 定义抽象处理者角色,Leade类,通过setSuccessor设置下一个请求处理者,定义handleRequest()函数,代码如下:
public abstract class Leader {

    protected String name;
    protected Leader successor;

    public Leader(String name) {
        this.name = name;
    }

    public void setSuccessor(Leader successor) {
        this.successor = successor;
    }

    public abstract void handleRequest(LeaveRequest request);

}
  • 定义具体处理者角色,实现Leader类,并实现Leader类中的handleRequest()函数,handleRequest()函数的处理逻辑为,如果处理者对象可以处理,那么进行处理,如果本次任务无法处理,那么就将本次任务传递给下一个处理者,代码如下:
public class Director extends Leader {

    public Director(String name) {
        super(name);
    }

    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getLeaveDays() < 3) {
            System.out.println("主任" + name + "审批员工" + request.getName() + "的请假条,请假天数为" + request.getLeaveDays() + "天");
        } else {
            if (null != this.successor)
                this.successor.handleRequest(request);
        }
    }
}
public class Manager extends Leader {

    public Manager(String name) {
        super(name);
    }

    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getLeaveDays() < 10) {
            System.out.println("经理" + name + "审批员工" + request.getName() + "的请假条,请假天数为" + request.getLeaveDays() + "天");
        } else {
            if (null != this.successor)
                this.successor.handleRequest(request);
        }
    }
}
public class GeneralManager extends Leader {

    public GeneralManager(String name) {
        super(name);
    }

    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getLeaveDays() < 30) {
            System.out.println("总经理" + name + "审批员工" + request.getName() + "的请假条,请假天数为" + request.getLeaveDays() + "天");
        } else {
            System.out.println(request.getName() + "请假天数过多,共" + request.getLeaveDays() + "天,请假申请不通过!");
        }
    }
}
  • 客户端类,构造了处理链,并向链头传入任务,代码如下:
public class Client {

    public static void main(String[] args) {
        Leader objDirector, objManager, objGeneralManager;

        objDirector = new Director("张胜男");
        objManager = new Manager("李斯艾");
        objGeneralManager = new GeneralManager("汪芜");

        objDirector.setSuccessor(objManager);
        objManager.setSuccessor(objGeneralManager);

        LeaveRequest r1 = new LeaveRequest("何小弟", 1);
        objDirector.handleRequest(r1);

        LeaveRequest r2 = new LeaveRequest("何二弟", 8);
        objDirector.handleRequest(r2);

        LeaveRequest r3 = new LeaveRequest("何三弟", 24);
        objDirector.handleRequest(r3);

        LeaveRequest r4 = new LeaveRequest("何四弟", 32);
        objDirector.handleRequest(r4);
    }

}

三、优劣分析

  • 请分析在总经理之后增加一个董事长,具备最高审判权限,应该对程序做什么改动?

    增加一个董事长类去实现Leader,然后在客户端重新建链即可,从这一点上看,符合“开闭原则”。

1. 优点

  1. 降低耦合度。它将请求的发送者和接收者解耦。
  2. 简化了对象。使得对象不需要知道链的结构。
  3. 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
  4. 增加新的请求处理类很方便。

2. 缺点

  1. 不能保证请求一定被接收。
  2. 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
  3. 可能不容易观察运行时的特征,有碍于除错。

猜你喜欢

转载自blog.csdn.net/Allen_Adolph/article/details/106879689