• 设计模式之责任链模式


    一、感性认识                                                                                         

        职责链模式的基本思路:

        首先职责链模式会定义一个所有处理请求的对象都要继承实现的抽象类,这样就有利于随时切换新的实现;

        其次每个处理请求对象只实现业务流程中的一步业务处理,这样使其变得简单;

        最后职责链模式会动态的来组合这些处理请求的对象,把它们按照流程动态组合起来,并要求它们依次调用,这样就动态的实现了流程。

    如果流程发生了变化,只要重新组合就好了;如果某个处理的业务功能发生了变化,一个方案是修改该处理对应的处理对象,另一个方案是直接提供一个新的实现,然后在组合流程的时候,用新的实现替换掉旧的实现就可以了。

    抽象处理者(Handler)角色

    package respon;
    
    /**
     * 定义职责对象
     * 
     * @author wy
     *
     */
    public abstract class TicketHandler {
        //持有下一个处理请求的对象
        protected TicketHandler successor = null;
    
        /**
         * 设置下一个处理请求的对象
         * @param successor
         */
        public void setSuccessor(TicketHandler successor) {
            this.successor = successor;
        }
        
        /**
         * 处理购票
         * @param mon
         * @return
         */
        public abstract String buyTicket(double mon); 
        
    }
    View Code

    具体处理者(ConcreteHandler)角色

    package respon;
    
    /**
     * 普通车票
     * 
     * @author wy
     *
     */
    public class CommonTicketHandler extends TicketHandler {
    
        @Override
        public String buyTicket(double mon) {
            String str = null;
            if (mon < 500) {
                if (mon > 300) {
                    str = "余额可以买一张普通票";
                } else {
                    str = "很遗憾,余额一张票也买不到";
                }
    
            } else {
                if (this.successor != null) {
                    return this.successor.buyTicket(mon);
                }
            }
            return str;
        }
    
    }
    View Code
    package respon;
    
    /**
     * 高铁票
     * 
     * @author wy
     *
     */
    public class HighSpeedRailTicketHandler extends TicketHandler {
        @Override
        public String buyTicket(double mon) {
            String str = null;
            if (mon < 1000) {
                if (mon > 500) {
                    str = "余额可以买一张高铁票";
                } else {
                    if (this.successor != null) {
                        return this.successor.buyTicket(mon);
                    }
                }
            } else {
                if (this.successor != null) {
                    return this.successor.buyTicket(mon);
                }
            }
            return str;
        }
    }
    View Code
    package respon;
    /**
     * 机票
     * 
     * @author wy
     *
     */
    public class PlaneTicketHandler extends TicketHandler {
    
        @Override
        public String buyTicket(double mon) {
            String str = null;
            if(mon > 1000){
                str = "余额可以买一张机票";
            } else {
                if(this.successor != null){
                    return this.successor.buyTicket(mon);
                }
            }
            return str;
        }
    
    }
    View Code

    二、什么是责任链模式                                                                              

        1)、责任链模式定义

         责任链模式是一种对象的行为模式。

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

        2)、责任链的结构和说明

                                                          

             责任链模式涉及到的角色:

    • Handler

            定义职责的接口,通常在这里定义处理请求的方法,可以在这里实现后继链。

    • ConcreteHandler

            实现职责的类,在这个类里面,实现对在它职责范围内请求的处理,如果不处理,就继续转发请求给后继者。

    • Client

            职责链的客户端,向链上的具体处理者对象提交请求,让职责链负责处理。

    三、责任链模式                                                                                   

       另种责任链示例

       Handler

    package respon.chain;
    
    /**
     * 定义职责对象
     * 
     * @author wy
     *
     */
    public interface TicketHandler {
        /**
         * 处理购票
         * 
         * @param mon
         * @return
         */
        public abstract String buyTicket(double mon, TicketHandlerChain chain);
    }
    View Code
    package respon.chain;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 处理链
     * 
     * @author wy
     *
     */
    public class TicketHandlerChain implements TicketHandler {
        private int index = 0;
        //票信息
        private String ticketMsg = null;
        private List<TicketHandler> ticketHandlerList = new ArrayList<TicketHandler>();
    
        public String getTicketMsg() {
            return ticketMsg;
        }
    
        public void setTicketMsg(String ticketMsg) {
            this.ticketMsg = ticketMsg;
        }
    
        public TicketHandlerChain addHandler(TicketHandler ticketHandler) {
            ticketHandlerList.add(ticketHandler);
            return this;
        }
    
        @Override
        public String buyTicket(double mon, TicketHandlerChain chain) {
            if (ticketHandlerList.size() == index) {
                return ticketMsg;
            }
    
            TicketHandler ticketHandlerChain = ticketHandlerList.get(index++);
            chain.setTicketMsg(ticketHandlerChain.buyTicket(mon, chain));
            return chain.buyTicket(mon, chain);
        }
    
    }
    View Code

       ConcreteHandler

    package respon.chain;
    
    /**
     * 普通车票
     * 
     * @author wy
     *
     */
    public class CommonTicketHandlerChain implements TicketHandler {
    
        @Override
        public String buyTicket(double mon, TicketHandlerChain chain) {
            String ticketMsg = chain.getTicketMsg();
            if (mon < 500) {
                if (mon > 300) {
                    ticketMsg = "余额可以买一张普通票";
                } else {
                    ticketMsg = "很遗憾,余额一张票也买不到";
                }
    
            }
            return ticketMsg;
        }
    
    }
    View Code
    package respon.chain;
    
    /**
     * 高铁票
     * 
     * @author wy
     *
     */
    public class HighSpeedRailTicketHandlerChain implements TicketHandler {
    
        @Override
        public String buyTicket(double mon, TicketHandlerChain chain) {
            String ticketMsg = chain.getTicketMsg();
            if (mon < 1000) {
                if (mon > 500) {
                    ticketMsg = "余额可以买一张高铁票";
                }
            }
            return ticketMsg;
        }
    
    }
    View Code
    package respon.chain;
    
    /**
     * 机票
     * 
     * @author wy
     *
     */
    public class PlaneTicketHandlerChain implements TicketHandler {
    
        @Override
        public String buyTicket(double mon, TicketHandlerChain chain) {
            String ticketMsg = chain.getTicketMsg();
            if(mon > 1000){
                ticketMsg = "余额可以买一张机票";
            } 
            return ticketMsg;
        }
    
    }
    View Code

       Client

    package respon.chain;
    
    public class ClientTest {
    
        public static void main(String[] args) {
            double mon = 1200;
            TicketHandlerChain ticketHandlerChain = new TicketHandlerChain().addHandler(new CommonTicketHandlerChain())
                    .addHandler(new HighSpeedRailTicketHandlerChain()).addHandler(new PlaneTicketHandlerChain());
            
            String ticketMsg = ticketHandlerChain.buyTicket(mon, ticketHandlerChain);
            System.out.println("购票信息: " + ticketMsg);
        }
    
    }
    View Code

    摘自 http://s i s h u ok.com/forum/blogPost/list/5815.html

    1)、模式功能

          职责链模式主要用来处理:“客户端发出一个请求,有多个对象都有机会来处理这一个请求,但是客户端不知道究竟谁会来处理他的请求”,这样的情况。也就是需要让请求者和接收者解耦,这样就可以动态的切换和组合接收者了。

    要注意在标准的职责链模式里面,是只要有对象处理了请求,这个请求就到此为止,不再被传递和处理了。

    如果是要变形使用职责链,就可以让这个请求继续传递,每个职责对象对这个请求进行一定的功能处理,从而形成一个处理请求的功能链。

    2)、隐式接收者

           当客户端发出请求的时候,客户端并不知道谁会真正处理他的请求,客户端只知道他提交请求的第一个对象。从第一个处理对象开始,整个职责链里面的对象,要么自己处理请求,要么继续转发给下一个接收者。

           也就是对于请求者而言,并不知道最终的接收者是谁,但是一般情况下,总是会有一个对象来处理的,因此称为隐式接收者。

    3)、如何构建链

           职责链的链怎么构建呢?这是个大问题,实现的方式也是五花八门,归结起来大致有以下一些方式。

           首先是按照实现的地方来说:

      • 可以实现在客户端,在提交请求前组合链,也就是在使用的时候动态组合链,称为外部链;
      • 也可以在Handler里面实现链的组合,算是内部链的一种;
      • 当然还有一种就是在各个职责对象里面,由各个职责对象自行决定后续的处理对象,这种实现方式要求每个职责对象除了进行业务处理外,还必须了解整个业务流程。

           按照构建链的数据来源,也就是决定了按照什么顺序来组合链的数据,又分为几种:

      • 一种就是在程序里面动态组合;
      • 也可以通过外部,比如数据库来获取组合的数据,这种属于数据库驱动的方式;
      • 还有一种方式就是通过配置文件传递进来,也可以是流程的配置文件。

    如果是从外部获取数据来构建链,那么在程序运行的时候,会读取这些数据,然后根据数据的要求来获取相应的对象,并组合起来。      

    还有一种是不需要构建链,因为已有的对象已经自然构成链了,这种情况多出现在组合模式构建的对象树中,这样子对象可以很自然的向上找到自己的父对象。就像部门人员的组织结构一样,顶层是总经理,总经理下面是各个部门的经理,部门经理下面是项目经理,项目经理下面是各个普通员工,自然就可以形成:普通员工à项目经理à部门经理à总经理这样的链。

    4)、谁来处理

    职责链中那么多处理对象,到底谁来处理请求呢,这个是在运行时期动态决定的。当请求被传递到某个处理对象的时候,这个对象会按照已经设定好的条件来判断,是否属于自己处理的范围,如果是就处理,如果不是就转发请求给下一个对象。

    5)、请求一定会被处理吗?

           在职责链模式中,请求不一定会被处理,因为可能没有合适的处理者,请求在职责链里面从头传递到尾,每个处理对象都判断不属于自己处理,最后请求就没有对象来处理。这一点是需要注意的。

    可以在职责链的末端始终加上一个不支持此功能处理的职责对象,这样如果传递到这里,就会出现提示,本职责链没有对象处理这个请求。

    四、责任链模式的优缺点                                                                       

         1)、请求者和接收者松散耦合
            在职责链模式里面,请求者并不知道接收者是谁,也不知道具体如何处理,请求者只是负责向职责链发出请求就可以了。而每个职责对象也不用管请求者或者是其它的职责对象,只负责处理自己的部分,其它的就交由其它的职责对象去处理。也就是说,请求者和接收者是完全解耦的。

         2)、动态组合职责
            职责链模式会把功能处理分散到单独的职责对象里面,然后在使用的时候,可以动态组合职责形成职责链,从而可以灵活的给对象分配职责,也可以灵活的实现和改变对象的职责。

         3)、产生很多细粒度对象
            职责链模式会把功能处理分散到单独的职责对象里面,也就是每个职责对象只是处理一个方面的功能,要把整个业务处理完,需要大量的职责对象的组合,这会产生大量的细粒度职责对象。

         4)、不一定能被处理
            职责链模式的每个职责对象只负责自己处理的那一部分,因此可能会出现某个请求,把整个链传递完了,都没有职责对象处理它。这就需要在使用职责链模式的时候注意,需要提供默认的处理,并且注意构建的链的有效性。

    五、责任链模式思考                                                                               

       职责链模式的本质:分离职责,动态组合

    分离职责是前提,只有先把复杂功能分开,拆分成很多的步骤和小的功能处理,然后才能合理规划和定义职责类,可以有很多的职责类来负责处理某一个功能,让每个职责类负责处理功能的某一个方面,在运行期间进行动态组合,形成一个处理的链,把这个链运行完,那么功能也就处理完了。

    动态组合才是职责链模式的精华所在,因为要实现请求对象和处理对象的解耦,请求对象不知道谁才是真正的处理对象,因此要动态的把可能的处理对象组合起来,由于组合的方式是动态的,这就意味着可以很方便的修改和添加新的处理对象,从而让系统更加灵活和具有更好的扩展性。

    当然这么做还会有一个潜在的优点,就是可以增强职责功能的复用性。如果职责功能是很多地方都可以使用的公共功能,那么它可以应用在多个职责链中复用。

    责任链模式在Tomcat中的应用:http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html

    由于本人经验有限,文章中难免会有错误,请浏览文章的您指正或有不同的观点共同探讨!

  • 相关阅读:
    2019 web安全基础知识学习
    nc语法和nc木马远程控制主机
    公钥、私钥、hash、数字签名、CA以及验证过程
    A5/1流加密理解和算法实现
    TCP/IP和OSI/RM以及协议端口
    【转】TCP/IP网络协议各层首部
    校园网 虚拟机VMware Linux桥接模式 无法上网 问题
    本地远程查看服务器tomcat 上虚拟机信息
    跨域访问的解决
    混合调用tk.mybatis.mapper 与 自编xml文件 的配置
  • 原文地址:https://www.cnblogs.com/exceptioneye/p/4869690.html
Copyright © 2020-2023  润新知