二手站網(wǎng)站怎做優(yōu)化課程體系
一、前言
????????Commons-chain是apache commons中的一個子項(xiàng)目,主要被使用在"責(zé)任鏈"的場景中,struts中action的調(diào)用過程,就是使用了"chain"框架做支撐.如果你的項(xiàng)目中,也有基于此種場景的需求,可以考慮使用它.
????????在責(zé)任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發(fā)出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統(tǒng)可以在不影響客戶端的情況下動態(tài)地重新組織和分配責(zé)任。即,在流水線上,屬于自己的就處理,不屬于自己的就丟給下一個處理。
(具體可以查看菜鳥教程:責(zé)任鏈模式 | 菜鳥教程)
二、?Commons Chain?
一、關(guān)系圖
二、接口詳解?
一、Command?接口
?Chain?中的具體某一步要執(zhí)行的命令。它只有一個方法:
boolean execute(Context context)?
如果返回?true?,那么表示?Chain?的處理結(jié)束,
如果返回 false ,那么表示Chain?中的其他命令不會被調(diào)用(也就是不執(zhí)行這個command);然后Chain?會繼續(xù)調(diào)用下一個?Command 。
從開始執(zhí)行到結(jié)束會出現(xiàn)三種情況:
1、?Command?返回?true;
2、Command?拋出異常;
3、一直執(zhí)行到?Chain?的末尾;
注意:context對象表示當(dāng)前"責(zé)任鏈"的上下文信息,它可以用來保存一些臨時變量(可以在command間共享)
二、?Chain?接口?
它表示“命令鏈”,要在其中執(zhí)行的命令,需要先添加到?Chain?中。?Chain?的父接口是?Command?,?ChainBase?實(shí)現(xiàn)了它。它有兩個方法:
//?可以添加多個command
void addCommand(Command var1);
//?ChainBase 執(zhí)行責(zé)任鏈的時候會調(diào)用這個方法,然后這個方法會調(diào)用每個command的execute方法去執(zhí)行。
boolean execute(Context var1) throws Exception;
由于直接繼承自
Command
接口,所以Chain也是一種Command。Command 類和Chain類的關(guān)系就是組合模式,Chain不僅由多個Command組成,而且自己也是Command。
三、?Context?接口?
它表示命令執(zhí)行的上下文,在命令間實(shí)現(xiàn)共享信息的傳遞。?Context?接口的父接口是?Map?,?ContextBase?實(shí)現(xiàn)了?Context?。
?另外觀察?
ContextBase
的構(gòu)造函數(shù)實(shí)現(xiàn),可以發(fā)現(xiàn)ContextBase
在初始化的時候會對本身使用反射進(jìn)行處理,提取自身的自定義屬性,并以鍵值對的形式推入到自身容器中,這樣可以直接通過context.get("beanPropertyName")來獲取相應(yīng)的值。
四、?Filter?接口?
當(dāng)有命令拋出錯誤時鏈就會非正常結(jié)束。在Commons Chain中,如果有命令拋出錯誤,鏈的執(zhí)行就會中斷。不論是運(yùn)行時錯誤(runtime exception)還是應(yīng)用錯誤(application exception),都會拋出給鏈的調(diào)用者。但是許多應(yīng)用都需要對在命令之外定義的錯誤做明確的處理。Commons Chain提供了Filter接口來滿足這個要求。
它的父接口是?Command?,它是一種特殊的?Command?。除了?Command?的?execute?,它還包括一個方法:
boolean postprocess(Context context, Exception exception)?
?Commons Chain?會在執(zhí)行了?Filter?的?execute?方法之后,執(zhí)行?postprocess?(不論?Chain?以何種方式結(jié)束)。
?Filter?的執(zhí)行?execute?的順序與?Filter?出現(xiàn)在?Chain?中出現(xiàn)的位置一致,但是執(zhí)行?postprocess?順序與之相反。
如:如果連續(xù)定義了?filter1?和?filter2?,那么execute?的執(zhí)行順序是:?filter1 -> filter2?;而?postprocess?的執(zhí)行順序是:?filter2 -> filter1?。postprocess 方法只會在鏈的最后執(zhí)行。
postprocess方法將在鏈執(zhí)行完畢或拋出錯誤后執(zhí)行。當(dāng)一個錯誤被拋出時, postprocess方法處理完后會返回true,表示錯誤處理已經(jīng)完成。鏈的執(zhí)行并不會就此結(jié)束,但是本質(zhì)上來說這個錯誤被捕捉而且不會再向外拋出。如果postprocess方法返回false,那錯誤會繼續(xù)向外拋出,然后鏈就會非正常結(jié)束。?
五、?Catalog?接口
它是邏輯命名的?Chain?和?Command?集合。通過使用它,?Command?的調(diào)用者不需要了解具體實(shí)現(xiàn)?Command?的類名,只需要通過名字就可以獲取所需要的?Command?實(shí)例。
比如:你在chain中則增加了Commond
??//?增加命令的順序也決定了執(zhí)行命令的順序
????public CommandChain(){
????????addCommand( new Command1());
????????addCommand( new Command2());
????????addCommand( new Command3());
????}
那你可以通過
Catalog catalog= CatalogFactoryBase.getInstance().getCatalog();
Command? cmd= catalog.getCommand( "command1");
獲取到對應(yīng)的command,然后單獨(dú)執(zhí)行這個Commmand;
??cmd.execute( context);
context:傳入的是?Context對象。
三、網(wǎng)上常用的使用方式?
public abstract class SellVehicleTemplate { // 銷售汽車 public void sellVehicle() { testDriveVehicle(); negotiateSale(); arrangeFinancing(); closeSale(); } // 試車public abstract void testDriveVehicle(); // 銷售談判public abstract void negotiateSale(); // 安排財(cái)務(wù)public abstract void arrangeFinancing(); // 結(jié)束銷售public abstract void closeSale();
}
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
// 試車(繼承Command)
public class TestDriveVehicle implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Test drive the vehicle"); return false; }
}
// 銷售談判
public class NegotiateSale implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Negotiate sale"); return false; }
}
// 安排財(cái)務(wù)
public class ArrangeFinancing implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Arrange financing"); return false; }
}
// 結(jié)束銷售
public class CloseSale implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Congratulations " + ctx.get("customerName") +", you bought a new car!"); return false; }
} // 定義責(zé)任鏈并測試
import org.apache.commons.chain.impl.ChainBase;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.impl.ContextBase;
// 繼承ChainBase
public class SellVehicleChain extends ChainBase { public SellVehicleChain() { super(); addCommand(new GetCustomerInfo()); addCommand(new TestDriveVehicle()); addCommand(new NegotiateSale()); addCommand(new ArrangeFinancing()); addCommand(new CloseSale()); } public static void main(String[] args) throws Exception { Command process = new SellVehicleChain(); Context ctx = new ContextBase(); process.execute(ctx); } // 運(yùn)行結(jié)果:
Test drive the vehicle
Negotiate sale
Arrange financing
Congratulations George Burdell, you bought a new car!
?Commons Chain提供了配置文件的方式定義責(zé)任鏈,在項(xiàng)目資源目錄中創(chuàng)建chain- config.xml文件
<catalog> <chain name="sell-vehicle"> <command id="GetCustomerInfo" className="com.jadecove.chain.sample.GetCustomerInfo"/> <command id="TestDriveVehicle" className="com.jadecove.chain.sample.TestDriveVehicle"/> <command id="NegotiateSale" className="com.jadecove.chain.sample.NegotiateSale"/> <command id="ArrangeFinancing" className="com.jadecove.chain.sample.ArrangeFinancing"/> <command id="CloseSale" className="com.jadecove.chain.sample.CloseSale"/> </chain>
</catalog>// 從xml配置中讀取
public class CatalogLoader { private static final String CONFIG_FILE = "/com/jadecove/chain/sample/chain-config.xml"; private ConfigParser parser; private Catalog catalog; public CatalogLoader() { parser = new ConfigParser(); } public Catalog getCatalog() throws Exception { if (catalog == null) { parser.parse(this.getClass().getResource(CONFIG_FILE)); } catalog = CatalogFactoryBase.getInstance().getCatalog(); return catalog; } public static void main(String[] args) throws Exception { CatalogLoader loader = new CatalogLoader(); Catalog sampleCatalog = loader.getCatalog(); Command command = sampleCatalog.getCommand("sell-vehicle"); Context ctx = new SellVehicleContext(); command.execute(ctx); }
}