责任链模式
一, 概念
是一个请求有多个对象来处理, 这些对象是一条链, 但具体由哪个对象来处理, 根据条件判断来确定, 如果不能处理会传递给该链中的下一个对象, 直到有对象处理它为止.
二, 使用场景
有多个对象可以处理同一个请求, 具体哪个对象处理该请求待运行时刻再确定.
在不明确指定接受者的情况下, 向多个对象中的一个提交一个请求.
可动态指定一组对象处理请求, 客户端可以动态创建职责链来处理请求.
三, UML 结构图
将接收者对象连成一条链, 并在该链上传递请求, 直到有一个接收者对象处理它. 通过让更多对象有机会处理请求, 避免了请求发送者和接收者之间的耦合.
责任链模式 UML.PNG
四, 代码示例
案例一: 公司处理员工请假请求
- Handler:
- public abstract class Handler {
- private Handler nextHandler;
- // 当前领导能审批通过的最多天数
- public int maxDay;
- protected Handler(int maxDay){
- this.maxDay = maxDay;
- }
- // 设置责任链中下一个处理请求的对象
- public void setNextHandler(Handler handler){
- nextHandler = handler;
- }
- protected void handleRequest(int day){
- if(day <= maxDay){
- reply(day);
- }else{
- if(nextHandler != null){
- // 审批权限不够, 继续上班
- nextHandler.handleRequest(day);
- }else{
- System.out.println("没有更高的领导审批了");
- }
- }
- }
- // 交由具体的 handler 来实现
- protected abstract void reply(int day);
- }
- ProjectManager:
- public class ProjectManager extends Handler{
- public ProjectManager(int maxDay) {
- super(maxDay);
- }
- @Override
- protected void reply(int day) {
- System.out.println(day+"天请假, 项目经理直接审批通过");
- }
- }
案例二: 销售团队处理客户需求
销售团队的层级关系:
- Sales:<=5%
- Manager:<=30%
- Director:<=40%
- Vice President:<=50%
- CEO:<=55%
- PriceHandler:
- /**
- * 价格处理人: 负责处理客户的折扣申请
- * 使用抽象类作为 Handler 的载体,
- * 因为 Handler 需要有一个指向自身类型的引用, 使用 interface 不方便
- * @author HCX
- *
- */
- public abstract class PriceHandler {
- /**
- * 直接后继, 用于传递请求
- * 指向自身类型的引用
- * protected: 使子类都可以访问到
- */
- protected PriceHandler successor;
- public void setSuccessor(PriceHandler successor) {
- this.successor = successor;
- }
- /**
- * 处理折扣请求
- * @param discount
- */
- public abstract void processDiscount(float discount);
- /**
- * 创建 PriceHandler 的工厂方法
- * @return
- */
- public static PriceHandler createPriceHandler() {
- PriceHandler sales = new Sales();
- PriceHandler manager = new Manager();
- PriceHandler director = new Director();
- PriceHandler vicePresident = new VicePresident();
- PriceHandler ceo = new CEO();
- // 设置直接后继
- sales.setSuccessor(manager);
- manager.setSuccessor(director);
- director.setSuccessor(vicePresident);
- vicePresident.setSuccessor(ceo);
- return sales;
- }
- }
- Sales:
- /**
- * 销售人员, 可以批准 5% 以内的折扣
- * @author HCX
- *
- */
- public class Sales extends PriceHandler {
- @Override
- public void processDiscount(float discount) {
- if(discount <= 0.05){
- System.out.format("%s 批准了折扣:%.2f%n", this.getClass().getName(),discount);
- }else{// 让直接后继来处理
- successor.processDiscount(discount);
- }
- }
- }
- Manager:
- /**
- * 销售经理, 可以批准 30% 以内的折扣
- * @author HCX
- *
- */
- public class Manager extends PriceHandler{
- @Override
- public void processDiscount(float discount) {
- if(discount <= 0.3){
- System.out.format("%s 批准了折扣:%.2f%n", this.getClass().getName(),discount);
- }else{// 超过直接传递给直接后继
- successor.processDiscount(discount);
- }
- }
- }
- Director:
- /**
- * 销售总监, 可以批准 40% 以内的折扣
- * @author HCX
- *
- */
- public class Director extends PriceHandler {
- @Override
- public void processDiscount(float discount) {
- if(discount <= 0.4){
- System.out.format("%s 批准了折扣:%.2f%n", this.getClass().getName(),discount);
- }else{// 超过直接传递给直接后继
- successor.processDiscount(discount);
- }
- }
- }
- VicePresident:
- /**
- * 销售副总裁, 可以批准 50% 以内的折扣
- * @author HCX
- *
- */
- public class VicePresident extends PriceHandler {
- @Override
- public void processDiscount(float discount) {
- if(discount <= 0.5){
- System.out.format("%s 批准了折扣:%.2f%n", this.getClass().getName(),discount);
- }else{// 超过直接传递给直接后继
- successor.processDiscount(discount);
- }
- }
- }
- CEO:
- /**
- * CEO, 可以批准 55% 以内的折扣
- * 折扣超出 55%, 拒绝申请
- * @author HCX
- *
- */
- public class CEO extends PriceHandler{
- @Override
- public void processDiscount(float discount) {
- if(discount <= 0.55){
- System.out.format("%s 批准了折扣:%.2f%n", this.getClass().getName(),discount);
- }else{// 让直接后继来处理
- System.out.format("%s 拒绝了折扣:%.2f%n", this.getClass().getName(),discount);
- }
- }
- }
- Customer:
- /**
- * 客户, 请求折扣
- * @author HCX
- *
- */
- public class Customer {
- private PriceHandler priceHandler;
- public void setPriceHandler(PriceHandler priceHandler) {
- this.priceHandler = priceHandler;
- }
- // 只关心折扣请求是否被处理了, 不关心被谁处理的.
- public void requestDiscount(float discount){
- priceHandler.processDiscount(discount);
- }
- public static void main(String[] args) {
- Customer customer = new Customer();
- customer.setPriceHandler(PriceHandler.createPriceHandler());
- Random random = new Random();
- for(int i=1;i<100;i++){
- System.out.println(i+":");
- customer.requestDiscount(random.nextFloat());
- }
- }
- }
修改: 在 Sales 和 manager 之间加入 Lead 层级:
加入了新的类 Lead, 并对工厂方法进行了改动
- Lead:
- /**
- * 销售小组长, 可以批准 15% 以内的折扣
- * @author HCX
- *
- */
- public class Lead extends PriceHandler{
- @Override
- public void processDiscount(float discount) {
- if(discount <= 0.15){
- System.out.format("%s 批准了折扣:%.2f%n", this.getClass().getName(),discount);
- }else{// 超过直接传递给直接后继
- successor.processDiscount(discount);
- }
- }
- }
- PriceHandler:
- /**
- * 价格处理人: 负责处理客户的折扣申请
- * 使用抽象类作为 Handler 的载体,
- * 因为 Handler 需要有一个指向自身类型的引用, 使用 interface 不方便
- * @author HCX
- *
- */
- public abstract class PriceHandler {
- /**
- * 直接后继, 用于传递请求
- * 指向自身类型的引用
- * protected: 使子类都可以访问到
- */
- protected PriceHandler successor;
- public void setSuccessor(PriceHandler successor) {
- this.successor = successor;
- }
- /**
- * 处理折扣请求
- * @param discount
- */
- public abstract void processDiscount(float discount);
- /**
- * 创建 PriceHandler 的工厂方法
- * @return
- */
- public static PriceHandler createPriceHandler() {
- PriceHandler sales = new Sales();
- PriceHandler lead = new Lead();
- PriceHandler manager = new Manager();
- PriceHandler director = new Director();
- PriceHandler vicePresident = new VicePresident();
- PriceHandler ceo = new CEO();
- // 设置直接后继
- sales.setSuccessor(lead);
- lead.setSuccessor(manager);
- manager.setSuccessor(director);
- director.setSuccessor(vicePresident);
- vicePresident.setSuccessor(ceo);
- return sales;
- }
- }
改进: OO 之中的原则: 单一职责原则, 在设计一个接口时, 应该只将与该接口业务相关的方法放在接口之中, 这样才能使设计更加健壮而不至于当变化发生时, 需要修改多处.
PriceHandler: 提供了处理业务的方法, 也提供了创建 PriceHandler 实例的工厂方法. 这两种方法在功能上不能类聚的, 两者之间没有关系, 该设计不符合单一职责原则.
命名规范不符合见名知意的原则.
把工厂方法抽取出来:
- PriceHandlerFactory:
- public class PriceHandlerFactory {
- /**
- * 创建 PriceHandler 的工厂方法
- * @return
- */
- public static PriceHandler createPriceHandler() {
- PriceHandler sales = new Sales();
- PriceHandler lead = new Lead();
- PriceHandler manager = new Manager();
- PriceHandler director = new Director();
- PriceHandler vicePresident = new VicePresident();
- PriceHandler ceo = new CEO();
- // 设置直接后继
- sales.setSuccessor(lead);
- lead.setSuccessor(manager);
- manager.setSuccessor(director);
- director.setSuccessor(vicePresident);
- vicePresident.setSuccessor(ceo);
- return sales;
- }
- }
- Customer:
- /**
- * 客户, 请求折扣
- * @author HCX
- *
- */
- public class Customer {
- private PriceHandler priceHandler;
- public void setPriceHandler(PriceHandler priceHandler) {
- this.priceHandler = priceHandler;
- }
- // 只关心折扣请求是否被处理了, 不关心被谁处理的.
- public void requestDiscount(float discount){
- priceHandler.processDiscount(discount);
- }
- public static void main(String[] args) {
- Customer customer = new Customer();
- customer.setPriceHandler(PriceHandlerFactory.createPriceHandler());
- Random random = new Random();
- for(int i=1;i<100;i++){
- System.out.println(i+":");
- customer.requestDiscount(random.nextFloat());
- }
- }
- }
- PriceHandler:
- /**
- * 价格处理人: 负责处理客户的折扣申请
- * 使用抽象类作为 Handler 的载体,
- * 因为 Handler 需要有一个指向自身类型的引用, 使用 interface 不方便
- * @author HCX
- *
- */
- public abstract class PriceHandler {
- /**
- * 直接后继, 用于传递请求
- * 指向自身类型的引用
- * protected: 使子类都可以访问到
- */
- protected PriceHandler successor;
- public void setSuccessor(PriceHandler successor) {
- this.successor = successor;
- }
- /**
- * 处理折扣请求
- * @param discount
- */
- public abstract void processDiscount(float discount);
- }
改进之后, Customer 类只依赖于 PriceHandler 和 PriceHandlerFactory 两个类, 并没有依赖实现的 PriceHandler:Sales 和 Manager 等; 因此耦合度较低.
五, 在实际中的应用
1try-catch 语句:
每一个 catch 语句是根据 Exception 异常类型进行匹配的, 一般会有多个 catch 语句, 就形成了一个责任链; 此时如果有一个 catch 语句与当前所要处理的异常 Exception 符合时, 该 Exception 就会交给相应的 catch 语句进行处理, 之后的 catch 语句就不会再执行了.
2异常处理机制:
方法的调用构成了一个栈, 当栈顶的方法产生异常时, 需要将异常抛出, 被抛出的异常沿着调用栈向下发展, 寻找一个处理的块, 被栈顶抛出的方法作为一个请求, 而调用栈上的每一个方法就相当于一个 handler, 该 Handler 即可以选择自行处理这个被抛出的异常, 也可以选择将异常沿着调用栈传递下去.
异常: 请求
调用栈中的每一级: Handler
调用栈中的 handler: 责任链
栈底元素: 上一级元素的直接后继
3过滤器链 (一般链条中只有一个对象处理请求, 但是过滤器链可以有多个对象同时处理请求)
过滤器链. PNG
4Spring Security 框架
通过多个 filter 类构成一个链条来处理 Http 请求, 从而为应用提供一个认证与授权的框架.
来源: http://www.jianshu.com/p/6f1a64b866a6