【Java设计模式】行为型设计模式-责任链模式(十六)

153 阅读7分钟

代码GitHub:github.com/lanjie6/Des…

责任链模式

  • 责任链模式,又叫职责链模式,将能够处理同一类请求的对象连成一条链,然后将请求的发送者和接收者进行了解耦。
  • 责任链模式会将所提交的请求沿着接收者的链进行传递,链上的对象逐个判断是否有能力处理该请求,如果能处理则处理,如果不能处理就传递给接收者链上的下一个对象,以此类推。

进一步阐述:责任链模式属于行为型模式,每个接收者都包含对另一个接收者的引用,以此形成接收者的链。

责任链模式包含三种角色:

  • Handler(抽象处理者):只能是一个抽象类,它定义了一个处理请求的方法, 同时包含另外 Handler的引用。
  • ConcreteHandler(具体处理者):继承了抽象处理者,负责处理它能处理的请求,并可以访问它的下一个处理者,如果能处理当前请求则处理,如果不能处理就将该请求交给下一个处理者去处理,从而形成一个责任链。
  • Request (请求对象):含有很多需要处理的属性,表示一个需要被处理的请求。

案例:税务系统的收税逻辑:月收入<=5000时不纳税;5000<月收入<=8000时,超过5000部分缴纳5%的税费;8000<月收入<=15000时,在缴纳超出5000部分的税费后超过8000部分缴纳10%的税费;15000<月收入<=30000时,在缴纳超出5000部分和超出8000部分的税费后超过15000部分缴纳15%的税费。税费管理服务TaxationService抽象类就是抽象处理者,税费计算请求对象TaxationCalculateRequest类就是请求对象,其他处理税费的类都是具体的处理者。PS:为了方便阅读,案例中的代码我们暂不考虑小数计算的精度问题

UML类图:

责任链模式.jpg

客户端Client:

/**
 * 使用责任链模式的客户端
 */
public class Client {
​
    public static void main(String[] args) {
        //创建各个税费计算对象
        TaxationService taxationService1 = new LessFiveThousandTaxationService();
        TaxationService taxationService2 = new LessEightThousandTaxationService();
        TaxationService taxationService3 = new LessFifteenThousandTaxationService();
        TaxationService taxationService4 = new LessThirtyThousandTaxationService();
​
        //构建计算的责任链
        taxationService1.setTaxationService(taxationService2);
        taxationService2.setTaxationService(taxationService3);
        taxationService3.setTaxationService(taxationService4);
​
        //计算月收入4500的税费
        TaxationCalculateRequest request = new TaxationCalculateRequest();
        request.setMonthlyIncome(4500);
        double taxation = taxationService1.calculateTaxation(request);
        System.out.println("月收入4500元应该缴纳的税费是:" + taxation);
​
        //计算月收入7500的税费
        request.setMonthlyIncome(7500);
        taxation = taxationService1.calculateTaxation(request);
        System.out.println("月收入7500元应该缴纳的税费是:" + taxation);
​
        //计算月收入11000的税费
        request.setMonthlyIncome(11000);
        taxation = taxationService1.calculateTaxation(request);
        System.out.println("月收入11000元应该缴纳的税费是:" + taxation);
​
        //计算月收入19000的税费
        request.setMonthlyIncome(19000);
        taxation = taxationService1.calculateTaxation(request);
        System.out.println("月收入19000元应该缴纳的税费是:" + taxation);
    }
}

税费管理服务TaxationService抽象类:

/**
 * 税费管理服务(抽象处理者)
 */
public abstract class TaxationService {
​
    /*
     * 持有一个自己类型的引用也就是持有下一个处理者
     */
    protected TaxationService taxationService;
​
    /**
     * 也就是setNext方法
     */
    public void setTaxationService(TaxationService taxationService) {
        this.taxationService = taxationService;
    }
​
    /**
     * 计算税费的方法
     *
     * @param request 税费请求对象
     * @return 应缴纳的税费
     */
    public abstract double calculateTaxation(TaxationCalculateRequest request);
​
}

5000元及以下税费计算服务LessFiveThousandTaxationService类:

/**
 * 5000元及以下税费计算服务(具体处理者)
 */
public class LessFiveThousandTaxationService extends TaxationService {
​
    /**
     * 计算税费的方法
     *
     * @param request 税费请求对象
     * @return 应缴纳的税费
     */
    public double calculateTaxation(TaxationCalculateRequest request) {
        if (request.getMonthlyIncome() <= 5000) {
            return 0.0;
        }
        return taxationService.calculateTaxation(request);
    }
}

8000元及以下税费计算服务LessEightThousandTaxationService类:

/**
 * 8000元及以下税费计算服务(具体处理者)
 */
public class LessEightThousandTaxationService extends TaxationService {
​
    /**
     * 计算税费的方法
     *
     * @param request 税费请求对象
     * @return 应缴纳的税费
     */
    public double calculateTaxation(TaxationCalculateRequest request) {
        double monthlyIncome = request.getMonthlyIncome();
        if (monthlyIncome <= 8000) {
            return request.getBaseTaxation() + (monthlyIncome - 5000) * 0.05;
        }
        request.setBaseTaxation((8000 - 5000) * 0.05);
        return taxationService.calculateTaxation(request);
    }
}

15000元及以下税费计算服务LessFifteenThousandTaxationService类:

/**
 * 15000元及以下税费计算服务(具体处理者)
 */
public class LessFifteenThousandTaxationService extends TaxationService {
​
    /**
     * 计算税费的方法
     *
     * @param request 税费请求对象
     * @return 应缴纳的税费
     */
    public double calculateTaxation(TaxationCalculateRequest request) {
        double monthlyIncome = request.getMonthlyIncome();
        if (monthlyIncome <= 15000) {
            return request.getBaseTaxation() + (monthlyIncome - 8000) * 0.1;
        }
        request.setBaseTaxation(request.getBaseTaxation() + (15000 - 8000) * 0.1);
        return taxationService.calculateTaxation(request);
    }
}

30000元及以下税费计算服务LessThirtyThousandTaxationService类:

/**
 * 30000元及以下税费计算服务(具体处理者)
 */
public class LessThirtyThousandTaxationService extends TaxationService {
​
    /**
     * 计算税费的方法
     *
     * @param request 税费请求对象
     * @return 应缴纳的税费
     */
    public double calculateTaxation(TaxationCalculateRequest request) {
        double monthlyIncome = request.getMonthlyIncome();
        if (monthlyIncome <= 30000) {
            return request.getBaseTaxation() + (monthlyIncome - 15000) * 0.15;
        }
        request.setBaseTaxation(request.getBaseTaxation() + (30000 - 15000) * 0.15);
        return taxationService.calculateTaxation(request);
    }
}

税费计算请求对象TaxationCalculateRequest类:

/**
 * 税费计算请求对象(请求对象)
 */
public class TaxationCalculateRequest {
​
    /*
     * 月收入
     */
    private double monthlyIncome;
​
    /*
     * 基础税费
     */
    private double baseTaxation;
​
    public double getBaseTaxation() {
        return baseTaxation;
    }
​
    public void setBaseTaxation(double baseTaxation) {
        this.baseTaxation = baseTaxation;
    }
​
    public double getMonthlyIncome() {
        return monthlyIncome;
    }
​
    public void setMonthlyIncome(double monthlyIncome) {
        this.monthlyIncome = monthlyIncome;
    }
}

运行结果:

责任链模式运行结果.png

总结:

  • 将请求和处理分开,实现解耦,提高了系统的灵活性遵守了单一职能原则。
  • 简化了请求对象,使请求对象不需要知道链的结构,遵守了迪米特法则。
  • 如果责任链比较长,那么系统性能会受到很大影响,因此需控制链中最大节点数量,一般通过在Handler 中设置一个最大节点数量,在setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链而影响系统性能的情况发生。
  • 调试不方便,采用了类似递归的方式,调试时逻辑可能比较复杂必须跟着链去一个一个地寻找出错点。

典型运用场景举例:

  • OA系统中的请假、文件审批等审批流程。
  • 学校教务系统中的奖学金审批、处分表扬审批。
  • 电商系统中的多重打折和优惠叠加计算折后价格的场景。

设计模式相关文章