Apache Commons Chain

基本對象
1. 接口。它是Commons Chain中最重要的接口,表示在Chain中的具體某一步要執行的命令。它只有一個方法:boolean execute(Context context)。若是返回true,那麼表示Chain的處理結束,Chain中的其餘命令不會被調用;返回false,則Chain會繼續調用下一個Command,直到: Command
-          返回true; Command
-          拋出異常; Command
-          的末尾; Chain
2. 接口。它表示命令執行的上下文,在命令間實現共享信息的傳遞。Context接口的父接口是Map,ContextBase實現了Context。對於web環境,可使用WebContext類及其子類(FacesWebContext、PortletWebContext和ServletWebContext)。 Context

3. 接口。它表示「命令鏈」,要在其中執行的命令,須要先添加到Chain中。Chain的父接口是Command,ChainBase實現了它。 Chainweb

4. 接口。它的父接口是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。 Filter
5. 接口。它是邏輯命名的Chain和Command集合。經過使用它,Command的調用者不須要了解具體實現Command的類名,只須要經過名字就能夠獲取所須要的Command實例。 Catalog
基本使用
1.         執行由順序的命令組成的流程,假設這條流程包含一、2和3步。
þ        實現要執行的命令步驟:

public class Command1 implements Command {
    public boolean execute(Context arg0) throws Exception {
        System.out.println("Command1 is done!");
        return false;
    }
}
public class Command2 implements Command {
    public boolean execute(Context arg0) throws Exception {
        System.out.println("Command2 is done!");    
        return false;
    }
}
public class Command3 implements Command {
    public boolean execute(Context arg0) throws Exception {
        System.out.println("Command3 is done!");
        return true;
    }
}

 

þ        註冊命令,建立執行的Chain:

public class CommandChain extends ChainBase {
    //增長命令的順序也決定了執行命令的順序
    public CommandChain(){
        addCommand( new Command1());
        addCommand( new Command2());
        addCommand( new Command3());
    }
   
    public static void main(String[] args) throws Exception{
        Command process = new CommandChain();
        Context ctx= new ContextBase();
        process.execute( ctx);
    }
}

 

2.         使用配置文件加載Command。除了在程序中註冊命令以外,還可使用配置文件來完成。
þ        對於例1,配置文件能夠寫成:

<?xml version="1.0" encoding="gb2312"?>
<catalog>
       <chain name="CommandChain">
        <!-- 定義的順序決定執行的順序 -->
              <command id="command1" className= "chain.Command1"/>
              <command id="command2" className= "chain.Command2"/>
              <command id="command3" className= "chain.Command3"/>
       </chain>

    <command name="command4" className="chain.Command1"/> apache

</catalog>

þ        裝入配置文件的代碼以下:

public class CatalogLoader {
    static final String cfgFile= "/chain/chain-cfg.xml";   
    public static void main(String[] args) throws Exception{
        CatalogLoader loader= new CatalogLoader();
        ConfigParser parser= new ConfigParser();
       
        parser.parse( loader.getClass().getResource( cfgFile));
        Catalog catalog= CatalogFactoryBase.getInstance().getCatalog();
        //加載Chain
        Command cmd= catalog.getCommand("CommandChain");
        Context ctx= new ContextBase();
        cmd.execute( ctx);
//加載Command
cmd= catalog.getCommand( "command4");
        cmd.execute( ctx);
    }
}

注意:使用配置文件的話,須要使用Commons Digester。而Digester則依賴:Commons Collections、Commons Logging和Commons BeanUtils。 post

3.         加載Catalog到web應用。爲了在web應用中加載Catalog,須要在對應的web.xml中添加:

<context-param> spa

 <param-name>org.apache.commons.chain.CONFIG_CLASS_RESOURCE</param-name> xml

 <param-value>resources/catalog.xml</param-value> 對象

</context-param> 索引

<listener> 接口

 <listener-class>org.apache.commons.chain.web.ChainListener</listener-class> ci

</listener>

缺省狀況下,Catalog會被加載到Servlet Context中,對應的屬性名字是「catalog」。所以獲取Catalog:
Catalog catalog = (Catalog) request.getSession()

                            .getServletContext().getAttribute("catalog"); get

4.         的使用。Filter是一種特殊的Command,它除了execute方法會被執行以外,同時還會在Chain執行完畢以後(不管是正常結束仍是異常結束)執行postprocess。所以,能夠將它和Servlet中的Filter作類比:execute至關於處理前操做(相對下一個Command來講),postprocess至關於處理後操做。Filter的使用以及配置和Command徹底同樣,爲了在Command1以前添加一個Filter: Filter
þ        定義Filter

public class Filter1 implements Filter {
    public boolean postprocess(Context arg0, Exception arg1) {
        System.out.println("Filter1 is after done!");
        return false;
    }
    public boolean execute(Context arg0) throws Exception {
        System.out.println("Filter1 is done!");
        return false;
    }
}

 

þ        修改配置文件,在上述的配置文件中的command1以前添加:
<command id="filter1" className= "chain.Filter1"/>
       Filter的還有一個經常使用的用法:對於異常的過濾。當Command拋出異常時,最終中會返回到最開始的調用處。有時指望不拋出這些異常,而在內部消化掉,那麼就能夠利用Filter。由於Commons Chain確保會調用已經執行了execute方法的Filter的postprocess方法,即便在出現異常時也是如此。所以,對應的postprocess方法能夠寫爲:
       public boolean postprocess(Context arg0, Exception arg1) {
        //返回true,表示非空異常已被處理,無需再拋出。
        //不然,異常會被拋出
        if( null!= arg1) return true;
        else return false;
    }
5.         對於複雜的Chain,可能須要使用內嵌的Chain,內嵌Chain能夠類比一個子過程。此時,可使用LookupCommand。以例1爲例,假設其中的command2須要擴展成爲一個子過程,那麼配置文件修改以下:

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
       <chain name="CommandChain">
              <command id="command1" className= "chain.Command1"/>
              <command id="filter1" className= "chain.Filter1"/>

              <command

className="org.apache.commons.chain.generic.LookupCommand"

                     name="chain_command3"

                     optional="true"/>
              <command id="command2" className= "chain.Command2"/>
       </chain>

       <chain name="chain_command3">

              <command id="command3" className= "chain.Command3"/>

       </chain>
</catalog>

其中,optional若是設爲true,那麼若是沒有找到對應的類時,程序不會拋出異常。此時,彷彿命令不存在同樣。若是爲false,那麼在找不到對應的類時,會拋出異常。
6.         的使用。配置文件的引入,使得Commons Chain的靈活性大大的提升。在實際的使用過程當中,存在着同一個Command被多個Chain使用的情形。若是每次都書寫Command的類名,尤爲是前面的包名特別長的狀況下,是很是枯燥的。而<define>的做用就是爲了解決這樣的麻煩。經過定義Command和Chain的別名,來簡化書寫。例5的配置文件,能夠書寫成: <define>

<?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>

 

總結
       Commons Chain實現了Chain of Responsebility和Command模式,其中的Catalog + 配置文件的方式使得調用方和Command的實現方的耦合度大大的下降,提升了靈活性。對於配置文件,一般能夠:
-          做爲Command的索引表,須要時按名字索引建立實例。
-          利用Chain以及內嵌Chain,完成一組連續任務和Command的複用,引入Filter能夠得到與Servlet Filter同樣的好處。

-          使用<define>定義別名,簡化書寫。

相關文章
相關標籤/搜索