• OOP设计模式[JAVA]——03职责链模式


    职责链模式 Responsibility of Chain

            在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。

    职责链模式的意图

            使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。[当然也有可能不被任何对象处理]

    职责链模式的结构


    参与者

    • Handler——定义一个处理请求的接口。如果需要,接口可以定义一个方法,以设定和返回对下家的引用。这个角色通常由一个JAVA抽象类或者JAVA接口实现。其示意性类图如下图所示。图中的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。

    • ConcreteHandler——处理它所负责的请求。
                                ——可访问它的后继者
                                ——如果可处理该请求,就处理;否则将该请求转发给它的后继者
    • Client——向链上的具体处理者对象提交请求

    协作

    当客户提交一个请求时,请求沿链传递直至有一个ConcreteHandler 对象负责处理它。


    使用场景

            职责链可能是一条直线、一个环链或者一个树结构的一部分。为了方便,我们使用一个简单的例子。公司人事的请假流程:请假一天组长批了即可、两到三天项目经理批了即可、三天以上需总经理批准。我们来看看源码实现:

            //抽象处理角色:

    package headfirst.ChainOfResponsibility;
    
    /**
     * @author Nick Lau
     * 抽象处理角色
     */
    public abstract class Handler {
        //持有处理请求的对象
        protected Handler successor = null;
        
        //取得后继者
        public Handler getSuccessor() {
            return successor;
        }
        
        //设置下一个处理请求的对象
        public void setSuccessor(Handler successor) {
            this.successor = successor;
        }
        
        /**
         * @param role 角色
         * @param days 请假天数
         * @return 审批成功或失败后返回的提示
         */
        public abstract String handleRequest(String role, int days);
    }
    

    下面是具体处理者的示意性源码。显然,处理者的逻辑非常简单,如果一个具体处理者有下家,就将请求传递给下家;如果没有下家,就处理掉。

    package headfirst.ChainOfResponsibility;
    
    /**
     * @author Nick Lau
     * TeamLeader处理请假事项
     */
    public class TeamLeader extends Handler {
    
        @Override
        public String handleRequest(String role, int days) {
            // TODO Auto-generated method stub
            String tips = "";
            if (days == 1) {
                if ("TeamLeader".equals(role)) {
                    tips = "TeamLeader agree " + days + " day(s) leave.";
                } else {
                    tips = "请假1天TeamLeader批准即可。";
                }
            } else {//传递给下一个继承者处理
                if (getSuccessor() != null)
                    return getSuccessor().handleRequest(role, days);
            }
            return tips;
        }
    
    }
    
    package headfirst.ChainOfResponsibility;
    
    public class ProjectManager extends Handler {
    
        @Override
        public String handleRequest(String role, int days) {
            // TODO Auto-generated method stub
            String tips = "";
            if (days > 1 && days <=3) {
                if ("ProjectManager".equals(role)) {
                    tips = "ProjectManager agree " + days + " day(s) leave.";
                } else {
                    tips = "请假1天TeamLeader批准即可;4天以上需总经理批准!";
                }
            } else {//如果还有下一个处理者则传递给下一个继承者处理
                if (getSuccessor() != null)
                    return getSuccessor().handleRequest(role, days);
            }
            return tips;
        }
    
    }
    
    package headfirst.ChainOfResponsibility;
    
    public class GeneralManager extends Handler{
    
        @Override
        public String handleRequest(String role, int days) {
            // TODO Auto-generated method stub
            String tips = "";
            if (days > 3) {
                if ("GeneralManager".equals(role)) {
                    tips = "GeneralManager agree " + days + " day(s) leave.";
                } else {
                    tips = role + "无权限处理" + days + "天请假事宜。";
                }
            } else {//传递给下一个继承者处理
                if (getSuccessor() != null)
                    return getSuccessor().handleRequest(role, days);
            }
            return tips;
        }
    
    }
    

            当然,在大多数情况下,这么简单的处理逻辑是没有实际用途的。真实的处理逻辑和所研究的系统商业逻辑密切相关,这里使用最简化的商业逻辑,有助于我们将精力集中到如何将模式应用到设计中去。

            客户端的源码清单如下:

    package headfirst.ChainOfResponsibility;
    
    public class Client {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Handler teamLeader = new TeamLeader();
            Handler projectManager = new ProjectManager();
            Handler generalManager = new GeneralManager();
            teamLeader.setSuccessor(projectManager);
            projectManager.setSuccessor(generalManager);
            
            String test1 = teamLeader.handleRequest("TeamLeader", 1);
            System.out.println(test1);
            String test2 = teamLeader.handleRequest("ProjectManager", 1);
            System.out.println(test2);
            System.out.print("+++++++++++++++++++++++++++++++++++++++++++++++++
    ");
            
            String test3 = teamLeader.handleRequest("ProjectManager", 3);
            System.out.println(test3);
            String test4 = teamLeader.handleRequest("GeneralManager", 3);
            System.out.println(test4);
            System.out.print("+++++++++++++++++++++++++++++++++++++++++++++++++
    ");
            
            String test5 = teamLeader.handleRequest("ProjectManager", 11);
            System.out.println(test5);
            String test6 = teamLeader.handleRequest("GeneralManager", 11);
            System.out.println(test6);
            System.out.print("+++++++++++++++++++++++++++++++++++++++++++++++++
    ");
        }
    
    }
    

    客户端输出如下:

    TeamLeader agree 1 day(s) leave.
    请假1天TeamLeader批准即可。
    +++++++++++++++++++++++++++++++++++++++++++++++++
    ProjectManager agree 3 day(s) leave.
    请假1天TeamLeader批准即可;4天以上需总经理批准!
    +++++++++++++++++++++++++++++++++++++++++++++++++
    ProjectManager无权限处理11天请假事宜。
    GeneralManager agree 11 day(s) leave.
    +++++++++++++++++++++++++++++++++++++++++++++++++

    效果

            职责链模式降低了请求的发送端和接收端之间的耦合,使多个对象都有机会处理这个请求。一个链可以是一条线、一棵树、也可以是一个环。链的拓扑结构可以是单连通的或多连通的,职责链模式并不指定职责链的拓扑结构。但是职责链模式要求在同一个时间里,命令只可以被传给一个下家(或被处理掉)而不能传给多个下家。

            下面情况可以使用职责链模式:

    1. 系统已经有一个由处理者对象组成的链。这个链可能由合成模式给出。
    2. 有多于一个的处理者对象会处理一个请求,而事先并不知道到底由哪一个处理者对象处理该请求。这个处理者对象是动态确定的。
    3. 系统想发出一个请求给多个处理者对象中的某一个,但是不明显指定是哪一个处理者对象。
    4. 处理一个请求的处理者对象集合需要动态地被指定。
  • 相关阅读:
    移动web开发视口viewport
    五层网络模型
    移动web开发理解设备像素、CSS像素、DPR
    git rebase简单使用
    position:fixed; IE6下解决办法。。
    (经典收藏)三十款最常用css选择器解析
    js控制搜索内容为空则搜索按钮不能用
    SAPBOE Universe 设计方法
    【转帖】开源BI系统分类
    【转贴】SQL2005 四个排名函数(row_number、rank、dense_rank和ntile)的比较
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3187111.html
Copyright © 2020-2023  润新知