java commons-chain_Apache commons chain 初探
Apache commons chain 是什么
Apache common chain 是對責(zé)任鏈設(shè)計(jì)模式的改造封裝,讓使用者更加方便的使用。
簡單回顧一下責(zé)任鏈設(shè)計(jì)模式
在閻宏博士的《JAVA與模式》一書中開頭是這樣描述責(zé)任鏈(Chain of Responsibility)模式的:
責(zé)任鏈模式是一種對象的行為模式。在責(zé)任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發(fā)出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統(tǒng)可以在不影響客戶端的情況下動態(tài)地重新組織和分配責(zé)任
關(guān)鍵點(diǎn):
鏈?zhǔn)且幌盗泄?jié)點(diǎn)的集合
鏈的各個節(jié)點(diǎn)可隨意拆分和組裝
使多個對象都有機(jī)會處理請求,從而避免請求的發(fā)送者和接受者之間的耦合關(guān)系, 將這個對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理他為止。
責(zé)任鏈適用的場景
有多個的對象可以處理一個請求,哪個對象處理該請求運(yùn)行時刻自動確定。
你想在不明確指定接受者的情況下,想過個對象中的一個提交一個請求。
可處理一個請求的對象集合應(yīng)該被動態(tài)指定。
簡單例子
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("還有責(zé)任鏈");
getNextHandler().doHandler();
} else {
System.out.println("我自己處理" + toString());
}
}
}
設(shè)計(jì)模式主體架構(gòu):
角色:
抽象處理者角色(Handler):定義出一個處理請求的接口。如果需要,接口可以定義 出一個方法以設(shè)定和返回對下家的引用。這個角色通常由一個Java抽象類或者Java接口實(shí)現(xiàn)。 具體處理者角色(ConcreteHandler):具體處理者接到請求后,可以選擇將請求處理掉,或者將請求傳給下家。由于具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家。 抽象處理者角色
public abstract class Handler {
/**
* 持有后繼的責(zé)任對象
*/
protected Handler successor;
/**
* 示意處理請求的方法,雖然這個示意方法是沒有傳入?yún)?shù)的
* 但實(shí)際是可以傳入?yún)?shù)的,根據(jù)具體需要來選擇是否傳遞參數(shù)
*/
public abstract void handleRequest();
/**
* 取值方法
*/
public Handler getSuccessor() {
return successor;
}
/**
* 賦值方法,設(shè)置后繼的責(zé)任對象
*/
public void setSuccessor(Handler successor) {
this.successor = successor;
}
}
具體處理者角色
public class ConcreteHandler extends Handler {
/**
* 處理方法,調(diào)用此方法處理請求
*/
@Override
public void handleRequest() {
/**
* 判斷是否有后繼的責(zé)任對象
* 如果有,就轉(zhuǎn)發(fā)請求給后繼的責(zé)任對象
* 如果沒有,則處理請求
*/
if(getSuccessor() != null)
{
System.out.println("放過請求");
getSuccessor().handleRequest();
}else
{
System.out.println("處理請求");
}
}
}
客戶端類:
public class Client {
public static void main(String[] args) {
//組裝責(zé)任鏈
Handler handler1 = new ConcreteHandler();
Handler handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
//提交請求
handler1.handleRequest();
}
}
Apache CommonsChain
CommonsChain實(shí)現(xiàn)了Chain of Responsebility和Command模式,其中的Catalog + 配置文件的方式使得調(diào)用方和Command的實(shí)現(xiàn)方的耦合度大大的降低,提高了靈活性。
如何使用
簡單寫了一個實(shí)現(xiàn):
/**
*
Test implementation of Chain that exposes the
* getCommands() method publicy.
*/
public class TestChain extends ChainBase {
/**
* 獲取責(zé)任鏈中所有加入的命令
* @return 責(zé)任鏈中的命令
*/
public Command[] getCommands() {
return (commands);
}
public static void main(String[] args) throws Exception {
TestChain testChain=new TestChain();
Context context=new ContextBase();
/**
* 加入執(zhí)行命令1
*/
testChain.addCommand(new Command() {
public boolean execute(Context context) throws Exception {
System.out.println("執(zhí)行命令1");
return false;
}
});
/**
* 加入執(zhí)行命令2
* 注意:返回值為true 表示執(zhí)行到此為止
*/
testChain.addCommand(new Command() {
public boolean execute(Context context) throws Exception {
System.out.println("執(zhí)行命令2");
return true;
}
});
/**
* 加入執(zhí)行命令3
*/
testChain.addCommand(new Command() {
public boolean execute(Context context) throws Exception {
System.out.println("執(zhí)行命令3");
return false;
}
});
//執(zhí)行鏈中的命令
testChain.execute(context);
//打印鏈中的所有命令
Command[] commands=testChain.getCommands();
for(Command command:commands){
System.out.println(command.getClass());
}
}
}
** 執(zhí)行結(jié)果 **
- 執(zhí)行命令1
- 執(zhí)行命令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中的具體某一步要執(zhí)行的命令。它只有一個方法:boolean execute(Context context)。如果返回true,那么表示Chain的處理結(jié)束,Chain中的其他命令不會被調(diào)用;返回false,則Chain會繼續(xù)調(diào)用下一個Command,直到:
[x] > Command返回true;
[x] > Command拋出異常;
[x] > Chain的末尾;
2. Context接口。它表示命令執(zhí)行的上下文,在命令間實(shí)現(xiàn)共享信息的傳遞。Context接口的父接口是Map,ContextBase實(shí)現(xiàn)了Context。對于web環(huán)境,可以使用WebContext類及其子類(FacesWebContext、PortletWebContext和ServletWebContext)。
3. Chain接口。它表示“命令鏈”,要在其中執(zhí)行的命令,需要先添加到Chain中。Chain的父接口是Command,ChainBase實(shí)現(xiàn)了它。
使用配置文件
test-config.xml
className="org.apache.commons.chain.impl.DelegatingCommand"/>
className="org.apache.commons.chain.impl.DelegatingCommand"/>
className="org.apache.commons.chain.impl.ExceptionCommand"/>
裝入配置文件
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
/**
*
The Catalog to contain our configured commands.
*/
protected Catalog catalog = null;
/**
*
The Context to use for execution tests.
*/
protected Context context = null;
/**
*
The ConfigParser instance under test.
*/
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;
}
/**
執(zhí)行測試方法
**/
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會在執(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。
5. Catalog接口。它是邏輯命名的Chain和Command集合。通過使用它,Command的調(diào)用者不需要了解具體實(shí)現(xiàn)Command的類名,只需要通過名字就可以獲取所需要的Command實(shí)例。
6.
的使用。配置文件的引入,使得Commons Chain的靈活性大大的提高。在實(shí)際的使用過程中,存在著同一個Command被多個Chain使用的情形。如果每次都書寫Command的類名,尤其是前面的包名特別長的情況下,是非常枯燥的。而
的作用就是為了解決這樣的麻煩。通過定義Command和Chain的別名,來簡化書寫。配置文件,可以書寫成:
className="org.apache.commons.chain.generic.LookupCommand"/>
參考:
總結(jié)
以上是生活随笔為你收集整理的java commons-chain_Apache commons chain 初探的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java switch char_Jav
- 下一篇: bat查看java进程 过滤_通过查找.