美文网首页
2019-08-21责任链模式

2019-08-21责任链模式

作者: 猫KK | 来源:发表于2019-08-21 20:26 被阅读0次

    将多个对象连成一条链,并沿这条链传递请求,直到有对象处理它为止

    就如同请假一样,你请假给你的直系领导,但是直系领导没有权利批假,他又会向他的领导提申请一样。一重一重的往上传递,直到有人能处理,在一重一重的回调回来。用代码来解释:
    定义一个领导的接口:

    public interface ILeader {
        /**
         * 请假结果
         *
         * @return 返回请假结果
         */
        String result(int date);
    }
    

    定义链,即上一级领导:

    public interface ILeave {
    
        /**
         * 设置领导
         *
         * @param nextLeader 领导
         */
        void nextLeader(ILeader nextLeader);
    }
    

    抽象一个领导,封装公用方法:

        
    public abstract class Leave implements ILeave, ILeader {
    
        //持有上级领导的引用
        protected ILeader leader;
    
        @Override
        public void nextLeader(ILeader nextLeader) {
            this.leader = nextLeader;
        }
    }
    

    具体一个领导:

    //组长
    public class TeamLeader extends Leave {
    
        //自己可以批的假的天数
        private final int batchLeaveDate = 2;
    
        @Override
        public String result(int date) {
            if (batchLeaveDate >= date) {
                //自己可以批这个假
                return "TeamLeader:请假批准";
            }
            //自己不可以批这个假,并且他有上级领导
            if (leader != null) {
                return leader.result(date);
            }
            return "TeamLeader:没人能批假";
        }
    }
    

    定义一个普通员工:

    public class Staff extends Leave {
    
        @Override
        public String result(int date) {
            //向上级请假,得到请假结果
            return leader.result(date);
        }
    }
    

    再多定义几个领导:

    //经理
    public class Manager extends Leave {
        //自己可以批的假的天数
        private final int batchLeaveDate = 4;
    
        @Override
        public String result(int date) {
            if (batchLeaveDate >= date) {
                //自己可以批这个假
                return "Manager:请假批准";
            }
            if (leader != null) {
                return leader.result(date);
            }
            return "Manager:没人能批假";
        }
    }
        
    //总经理
    public class GeneralManager extends Leave {
        //自己可以批的假的天数
        private final int batchLeaveDate = 10;
    
        @Override
        public String result(int date) {
            if (batchLeaveDate >= date) {
                //自己可以批这个假
                return "GeneralManager:请假批准";
            }
            if (leader != null) {
                return leader.result(date);
            }
            return "GeneralManager:没人能批假";
        }
    }
        
    //老板
    public class Boss extends Leave {
        //自己可以批的假的天数
        private final int batchLeaveDate = 30;
    
        @Override
        public String result(int date) {
            if (batchLeaveDate >= date) {
                //自己可以批这个假
                return "Boss:请假批准";
            }
            if (leader != null) {
                return leader.result(date);
            }
            return "Boss:走人吧,没有这么长的假";
        }
    }
    

    在客户端中使用:

    public class Client {
        public static void main(String[] args) {
            //创建各个领导对象,即多个对象
            Boss boss = new Boss();
            GeneralManager generalManager = new GeneralManager();
            Manager manager = new Manager();
            TeamLeader teamLeader = new TeamLeader();
            //设置各个领导的上级领导,即构成一条链
            teamLeader.nextLeader(manager);
            manager.nextLeader(generalManager);
            generalManager.nextLeader(boss);
    
            //创建员工对象
            Staff staff = new Staff();
            //设置员工对象的领导
            staff.nextLeader(teamLeader);
            //请假一天,得到结果
            String result = staff.result(1);
            System.out.println(result);
        }
    }
    

    到这里,责任链模式就完成,还有一种写法,就是Okhttp的拦截器,需要多一个辅助类,下面仿照okhttp的责任链,重新定义 ILeader 接口:

    public interface ILeader {
        //得到结果
        String result(Chain chain);
    
        //定义一个链的接口
        interface Chain {
            //定义需要传递的参数,即请假天数
            int leaveDate();
            //得到结果
            String proceed(int date);
        }
    }
    

    增加一个辅助类:

    //实现ILeader.Chain接口
    public class Company implements ILeader.Chain {
    
        private List<ILeader> leaders;
        private int index, leaveDate;
        //构造方法传递所有的领导列表,当前的领导下标,需要传递的参数
        public Company(List<ILeader> leaders, int leaveDate, int index) {
            this.leaders = leaders;
            this.index = index;
            this.leaveDate = leaveDate;
        }
    
        @Override
        public int leaveDate() {
            //返回需要传递的参数
            return leaveDate;
        }
    
        @Override
        public String proceed(int date) {
            //在 proceed 方法中从新创建一个Company对象,注意 index 下标加 1 
            //代表了下一个领导
            Company next = new Company(leaders, date, index + 1);
            //根据下标,获取领导
            ILeader leader = leaders.get(index);
             //调用领导的处理方法,处理这个请假
            return leader.result(next);
        }
    }
    

    重新编写领导:

    //实现ILeader 接口
    public class TeamLeader implements ILeader {
    
        //自己可以批的假的天数
        private final int batchLeaveDate = 2;
    
        @Override
        public String result(Chain chain) {
            //通过辅助类,获取传递的参数,即请假天数
            int leaveDate = chain.leaveDate();
            //判断自己是否可以批假
            if (batchLeaveDate >= leaveDate) {
                return "TeamLeader:批假了";
            }
            //不可以,通过辅助类来走下一个领导
            return chain.proceed(chain.leaveDate());
        }
    }
    

    再来一个领导

    public class Boss implements ILeader {
    
        //自己可以批的假的天数
        private final int batchLeaveDate = 30;
    
        @Override
        public String result(Chain chain) {
            int leaveDate = chain.leaveDate();
            if (batchLeaveDate >= leaveDate) {
                return "Boss:批假了";
            }
            return "走人吧";
        }
    }
    

    在 Client 中使用:

        
    public class Client {
        public static void main(String[] args) {
            //定义领导列表
            List<ILeader> leaders = new ArrayList<>();
            //往列表中新添加领导,注意,先添加会先经过
            //因为是通过index下表来获取的
            leaders.add(new TeamLeader());
            leaders.add(new Boss());
            //创建辅助类Company,注意,index 初始值为0,需要传递的参数和下面一致即可
            Company company = new Company(leaders, 35, 0);
            //调用请假,获取请假结果
            String result = company.proceed(35);
            System.out.println(result);
        }
    }
    

    上面这种就是仿照okhttp的拦截器写的责任链,相比上一种,就不需要逐个对象设置链。注意,使用这种写法一定有一个是返回结果的,即总会有一个终结点,否则会出现数组下标越界的错误。

    相关文章

      网友评论

          本文标题:2019-08-21责任链模式

          本文链接:https://www.haomeiwen.com/subject/thtwsctx.html