文档章节

Apache commons chain 初探

smallcarp
 smallcarp
发布于 2017/04/07 21:04
字数 1963
阅读 63
收藏 0
点赞 0
评论 0

Apache commons chain 是什么

Apache common chain 是对责任链设计模式的改造封装,让使用者更加方便的使用。

简单回顾一下责任链设计模式

在阎宏博士的《JAVA与模式》一书中开头是这样描述责任链(Chain of Responsibility)模式的:

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

关键点

  • 链是一系列节点的集合
  • 链的各个节点可随意拆分和组装

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系, 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。

责任链适用的场景

  • 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。

  • 你想在不明确指定接受者的情况下,想过个对象中的一个提交一个请求。

  • 可处理一个请求的对象集合应该被动态指定。

简单例子

abstract class Handler {

    private Handler nextHandler;

    public Handler getNextHandler() {
        return nextHandler;
    }

    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public abstract void doHandler();

}

class ConcreteHandler extends Handler {

    @Override
    public void doHandler() {

        if (getNextHandler() != null) {

            System.out.println("还有责任链");
            getNextHandler().doHandler();
        } else {

            System.out.println("我自己处理" + toString());
        }

    }
}

设计模式主体架构

角色

抽象处理者角色(Handler):定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。 具体处理者角色(ConcreteHandler):具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。 抽象处理者角色

public abstract class Handler {  
      
    /** 
     * 持有后继的责任对象 
     */  
    protected Handler successor;  
    /** 
     * 示意处理请求的方法,虽然这个示意方法是没有传入参数的 
     * 但实际是可以传入参数的,根据具体需要来选择是否传递参数 
     */  
    public abstract void handleRequest();  
    /** 
     * 取值方法 
     */  
    public Handler getSuccessor() {  
        return successor;  
    }  
    /** 
     * 赋值方法,设置后继的责任对象 
     */  
    public void setSuccessor(Handler successor) {  
        this.successor = successor;  
    }  
      
}  

具体处理者角色

public class ConcreteHandler extends Handler {  
    /** 
     * 处理方法,调用此方法处理请求 
     */  
    @Override  
    public void handleRequest() {  
        /** 
         * 判断是否有后继的责任对象 
         * 如果有,就转发请求给后继的责任对象 
         * 如果没有,则处理请求 
         */  
        if(getSuccessor() != null)  
        {              
            System.out.println("放过请求");  
            getSuccessor().handleRequest();              
        }else  
        {              
            System.out.println("处理请求");  
        }  
    }  
  
} 

客户端类

public class Client {  
  
    public static void main(String[] args) {  
        //组装责任链  
        Handler handler1 = new ConcreteHandler();  
        Handler handler2 = new ConcreteHandler();  
        handler1.setSuccessor(handler2);  
        //提交请求  
        handler1.handleRequest();  
    }  
  
}  

Apache CommonsChain

CommonsChain实现了Chain of Responsebility和Command模式,其中的Catalog + 配置文件的方式使得调用方和Command的实现方的耦合度大大的降低,提高了灵活性。

如何使用

简单写了一个实现:

/**
 * <p>Test implementation of <code>Chain</code> that exposes the
 * <code>getCommands()</code> method publicy.</p>
 */

public class TestChain extends ChainBase {


    /**
     * 获取责任链中所有加入的命令
     * @return 责任链中的命令
     */
    public Command[] getCommands() {

    return (commands);

    }
 public static void main(String[] args) throws Exception {
        TestChain testChain=new TestChain();
        Context context=new ContextBase();
        /**
         * 加入执行命令1
         */
        testChain.addCommand(new Command() {
            public boolean execute(Context context) throws Exception {
                System.out.println("执行命令1");
                return false;
            }
        });
        /**
         * 加入执行命令2
         * 注意:返回值为true 表示执行到此为止
         */
        testChain.addCommand(new Command() {
            public boolean execute(Context context) throws Exception {
                System.out.println("执行命令2");
                return true;
            }
        });
        /**
         * 加入执行命令3
         */
        testChain.addCommand(new Command() {
            public boolean execute(Context context) throws Exception {
                System.out.println("执行命令3");
                return false;
            }
        });
        //执行链中的命令
        testChain.execute(context);
        //打印链中的所有命令
        Command[] commands=testChain.getCommands();
        for(Command command:commands){
            System.out.println(command.getClass());
        }
    }

}

** 执行结果 **

- 执行命令1
- 执行命令2
- class org.apache.commons.chain.config.TestChain$1
- class org.apache.commons.chain.config.TestChain$2
- class org.apache.commons.chain.config.TestChain$3

基本对象

  • 1. Command接口。它是Commons Chain中最重要的接口,表示在Chain中的具体某一步要执行的命令。它只有一个方法:boolean execute(Context context)。如果返回true,那么表示Chain的处理结束,Chain中的其他命令不会被调用;返回false,则Chain会继续调用下一个Command,直到:

  • [x] > Command返回true;

  • [x] > Command抛出异常;

  • [x] > Chain的末尾;

  • 2. Context接口。它表示命令执行的上下文,在命令间实现共享信息的传递。Context接口的父接口是Map,ContextBase实现了Context。对于web环境,可以使用WebContext类及其子类(FacesWebContext、PortletWebContext和ServletWebContext)。

  • 3. Chain接口。它表示“命令链”,要在其中执行的命令,需要先添加到Chain中。Chain的父接口是Command,ChainBase实现了它。

使用配置文件

test-config.xml
<catalog>
  <chain name="Execute">
    <command id="1"
        className="org.apache.commons.chain.impl.DelegatingCommand"/>
    <command id="2"
        className="org.apache.commons.chain.impl.DelegatingCommand"/>
    <command  id="3"
        className="org.apache.commons.chain.impl.ExceptionCommand"/>
  </chain>
</catalog>

装入配置文件

public class ConfigParserTestCase extends TestCase {


    private static final String DEFAULT_XML =
        "/org/apache/commons/chain/config/test-config.xml";
     // ------------------------------------------------------------ Constructors
    /**
     * Construct a new instance of this test case.
     *
     * @param name Name of the test case
     */
    public ConfigParserTestCase(String name) {
        super(name);
    }
    // ------------------------------------------------------ Instance Variables
    /**
     * <p>The <code>Catalog</code> to contain our configured commands.</p>
     */
    protected Catalog catalog = null;
    /**
     * <p>The <code>Context</code> to use for execution tests.</p>
     */
    protected Context context = null;
    /**
     * <p>The <code>ConfigParser</code> instance under test.</p>
     */
    protected ConfigParser parser = null;
    // ---------------------------------------------------- Overall Test Methods
    /**
     * Set up instance variables required by this test case.
     */
    public void setUp() {
        catalog = new CatalogBase();
        context = new ContextBase();
        parser = new ConfigParser();
    }
    /**
     * Return the tests included in this test suite.
     */
    public static Test suite() {
        return (new TestSuite(ConfigParserTestCase.class));
    }
    /**
     * Tear down instance variables required by this test case.
     */
    public void tearDown() {
        parser = null;
        context = null;
        catalog = null;
    }
    /**
       执行测试方法
    **/
    public void testExecute2c() throws Exception {

        load(DEFAULT_XML);
        try {
            catalog.getCommand("Execute").execute(context);
        } catch (ArithmeticException e) {
            assertEquals("Correct exception id",
                         "3", e.getMessage());
        }
        checkExecuteLog("1/2/3");
    }
    /** 
       从配置文件中加载配置信息
    **/
    protected void load(String path) throws Exception {
        parser.parse(this.getClass().getResource(path));
        catalog = CatalogFactoryBase.getInstance().getCatalog();
    }


}

注意:使用配置文件的话,需要使用Commons Digester。而Digester则依赖:Commons Collections、Commons Logging和Commons BeanUtils。

  • 4. Filter接口。它的父接口是Command,它是一种特殊的Command。除了Command的execute,它还包括一个方法:boolean postprocess(Context context, Exception exception)。Commons Chain会在执行了Filter的execute方法之后,执行postprocess(不论Chain以何种方式结束)。Filter的执行execute的顺序与Filter出现在Chain中出现的位置一致,但是执行postprocess顺序与之相反。如:如果连续定义了filter1和filter2,那么execute的执行顺序是:filter1 -> filter2;而postprocess的执行顺序是:filter2 -> filter1。
  • 5. Catalog接口。它是逻辑命名的Chain和Command集合。通过使用它,Command的调用者不需要了解具体实现Command的类名,只需要通过名字就可以获取所需要的Command实例。
  • 6.<define>的使用。配置文件的引入,使得Commons Chain的灵活性大大的提高。在实际的使用过程中,存在着同一个Command被多个Chain使用的情形。如果每次都书写Command的类名,尤其是前面的包名特别长的情况下,是非常枯燥的。而<define>的作用就是为了解决这样的麻烦。通过定义Command和Chain的别名,来简化书写。配置文件,可以书写成:
<?xml version="1.0" encoding="gb2312"?>
<catalog>
    <!-- Command的别名,以后直接使用即可 -->
       <define name="command1" className="chain.Command1"/>
       <define name="command2" className="chain.Command2"/>
       <define name="command3" className="chain.Command3"/>
       <define name="filter1" className="chain.Filter1"/>
       <define name="lookupCommand"
                  className="org.apache.commons.chain.generic.LookupCommand"/>
      
       <chain name="CommandChain">
              <command1 id="1"/>
              <filter1 id="2"/>
              <lookupCommand name="chain_command3" optional="true"/>
              <command2 id="3"/>
       </chain>
      
       <chain name="chain_command3">
              <command3 id="3"/>
       </chain>
      
       <command1 name="command4"/>
</catalog>

参考:

© 著作权归作者所有

共有 人打赏支持
smallcarp
粉丝 1
博文 3
码字总数 6329
作品 0
泰安
Commons Chain

Commons Chain 是一个实现了责任链设计模式的 Java 类库。 示例代码: package org.apache.commons.chain.mailreader.commands; import org.apache.commons.chain.Command; import org.apac......

匿名 ⋅ 2010/05/17 ⋅ 0

Apache Commons Chain

基本对象 1. 接口。它是Commons Chain中最重要的接口,表示在Chain中的具体某一步要执行的命令。它只有一个方法:boolean execute(Context context)。如果返回true,那么表示Chain的处理结束...

疯狂的艺术家 ⋅ 2011/03/31 ⋅ 0

ClassCastException

@莫迪 你好,想跟你请教个问题: 我在Eclipse下配置的struts1.3的小工程,在表单提交后就出现下面的错误,很是费解,该导入的包也都有,包的继承关系也没弄错,为什么就不能cast ActionForm...

陈利涛 ⋅ 2014/05/08 ⋅ 1

ClassCastException

@红薯 你好,想跟你请教个问题: 我在Eclipse下配置的struts1.3的小工程,在表单提交后就出现下面的错误,很是费解,该导入的包也都有,包的继承关系也没弄错,为什么就不能cast ActionForm...

陈利涛 ⋅ 2014/05/08 ⋅ 5

项目部署JBOSS启动成功了,但是访问JSP报如下错误,高手解答,在线等,谢谢!

20:48:02,866 ERROR [[jsp]] Servlet.service() for servlet jsp threw exception java.lang.NoSuchMethodError: org.apache.jasper.runtime.PageContextImpl.evaluateExpression(Ljava/lang......

RomeoZhou ⋅ 2013/09/27 ⋅ 1

异常:javax.el.PropertyNotFoundException: Property 'mainGroupCode' not found on type java.lang.String

严重: Servlet.service() for servlet jsp threw exceptionjavax.el.PropertyNotFoundException: Property 'mainGroupCode' not found on type java.lang.Stringat javax.el.BeanELResolver$......

chrisd ⋅ 2016/11/01 ⋅ 0

javaweb 应用部署到SAE 出错,本地运行不会出错

请各位大神解答一下,该如何解决,急等答案。。。 Caused by: java.lang.IllegalArgumentException: Property 'class' is not present at org.apache.commons.chain.impl.ContextBase.elimin......

qihulingdeyu ⋅ 2014/07/05 ⋅ 2

Apache Commons 常用工具包

Apache Commons是一个非常有用的工具包,解决各种实际的通用问题,下面是一个简述表,详细信息访问http://jakarta.apache.org/commons/index.html BeanUtils Commons-BeanUtils 提供对 Java...

K_ONE ⋅ 2016/05/04 ⋅ 0

jbpm发布流程时报这个错是什么原因???

2015-9-17 13:31:54 org.hibernate.util.JDBCExceptionReporter logExceptions 警告: SQL Error: 17090, SQLState: null 2015-9-17 13:31:54 org.hibernate.util.JDBCExceptionReporter logE......

Ray阿迪 ⋅ 2015/09/17 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

知乎Java数据结构

作者:匿名用户 链接:https://www.zhihu.com/question/35947829/answer/66113038 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 感觉知乎上嘲讽题主简...

颖伙虫 ⋅ 今天 ⋅ 0

Confluence 6 恢复一个站点有关使用站点导出为备份的说明

推荐使用生产备份策略。我们推荐你针对你的生产环境中使用的 Confluence 参考 Production Backup Strategy 页面中的内容进行备份和恢复(这个需要你备份你的数据库和 home 目录)。XML 导出备...

honeymose ⋅ 今天 ⋅ 0

JavaScript零基础入门——(九)JavaScript的函数

JavaScript零基础入门——(九)JavaScript的函数 欢迎回到我们的JavaScript零基础入门,上一节课我们了解了有关JS中数组的相关知识点,不知道大家有没有自己去敲一敲,消化一下?这一节课,...

JandenMa ⋅ 今天 ⋅ 0

火狐浏览器各版本下载及插件httprequest

各版本下载地址:http://ftp.mozilla.org/pub/mozilla.org//firefox/releases/ httprequest插件截至57版本可用

xiaoge2016 ⋅ 今天 ⋅ 0

Docker系列教程28-实战:使用Docker Compose运行ELK

原文:http://www.itmuch.com/docker/28-docker-compose-in-action-elk/,转载请说明出处。 ElasticSearch【存储】 Logtash【日志聚合器】 Kibana【界面】 答案: version: '2'services: ...

周立_ITMuch ⋅ 今天 ⋅ 0

使用快嘉sdkg极速搭建接口模拟系统

在具体项目研发过程中,一旦前后端双方约定好接口,前端和app同事就会希望后台同事可以尽快提供可供对接的接口方便调试,而对后台同事来说定好接口还仅是个开始、设计流程,实现业务逻辑,编...

fastjrun ⋅ 今天 ⋅ 0

PXE/KickStart 无人值守安装

导言 作为中小公司的运维,经常会遇到一些机械式的重复工作,例如:有时公司同时上线几十甚至上百台服务器,而且需要我们在短时间内完成系统安装。 常规的办法有什么? 光盘安装系统 ===> 一...

kangvcar ⋅ 昨天 ⋅ 0

使用Puppeteer撸一个爬虫

Puppeteer是什么 puppeteer是谷歌chrome团队官方开发的一个无界面(Headless)chrome工具。Chrome Headless将成为web应用自动化测试的行业标杆。所以我们很有必要来了解一下它。所谓的无头浏...

小草先森 ⋅ 昨天 ⋅ 0

Java Done Right

* 表示难度较大或理论性较强。 ** 表示难度更大或理论性更强。 【Java语言本身】 基础语法,面向对象,顺序编程,并发编程,网络编程,泛型,注解,lambda(Java8),module(Java9),var(...

风华神使 ⋅ 昨天 ⋅ 0

Linux系统日志

linux 系统日志 /var/log/messages /etc/logrotate.conf 日志切割配置文件 https://my.oschina.net/u/2000675/blog/908189 logrotate 使用详解 dmesg 命令 /var/log/dmesg 日志 last命令,调......

Linux学习笔记 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部