類和接口關(guān)系分析
接口定義
Command 命令接口
public abstract interface Command
{
public static final boolean CONTINUE_PROCESSING = 0;
public static final boolean PROCESSING_COMPLETE = 1;
public abstract boolean execute(Context paramContext)
throws Exception;
}
Context 上下文接口
public abstract interface Context extends Map
{
}
Chain 執(zhí)行鏈接口
public abstract interface Chain extends Command
{
public abstract void addCommand(Command paramCommand);
public abstract boolean execute(Context paramContext)
throws Exception;
}
Filter 攔截器接口(相當(dāng)于一種特殊的命令)
public abstract interface Filter extends Command
{
//后置處理
public abstract boolean postprocess(Context paramContext, Exception paramException);
}
ContextBase 上下文實(shí)現(xiàn)類 拓展的是HashMap
public class ContextBase extends HashMap
implements Context
{
//這里可以根據(jù)自己的業(yè)務(wù)定制上下文
}
ChainBase 執(zhí)行鏈實(shí)現(xiàn)類
public class ChainBase
implements Chain
{
//要執(zhí)行的命令數(shù)組
protected Command[] commands = new Command[0];
protected boolean frozen = false;
public ChainBase()
{
}
public ChainBase(Command command)
{
addCommand(command);
}
public ChainBase(Command[] commands)
{
if (commands == null) {
throw new IllegalArgumentException();
}
for (int i = 0; i < commands.length; ++i)
addCommand(commands[i]);
}
public ChainBase(Collection commands)
{
if (commands == null) {
throw new IllegalArgumentException();
}
Iterator elements = commands.iterator();
while (elements.hasNext())
addCommand((Command)elements.next());
}
public void addCommand(Command command)
{
if (command == null) {
throw new IllegalArgumentException();
}
if (this.frozen) {
throw new IllegalStateException();
}
Command[] results = new Command[this.commands.length + 1];
System.arraycopy(this.commands, 0, results, 0, this.commands.length);
results[this.commands.length] = command;
this.commands = results;
}
//執(zhí)行命令
public boolean execute(Context context)
throws Exception
{
if (context == null) {
throw new IllegalArgumentException();
}
this.frozen = true;
//執(zhí)行結(jié)果
boolean saveResult = false;
Exception saveException = null;
int i = 0;
int n = this.commands.length;
label79:
for (i = 0; i < n; ++i) {
try {
//返回執(zhí)行結(jié)果如果為true就代表不往下執(zhí)行
saveResult = this.commands[i].execute(context);
if (saveResult)
break label79;
}
catch (Exception e) {
//異常處理
saveException = e;
break label79;
}
}
if (i >= n) {
label79: --i;
}
//過濾器處理狀態(tài)
boolean handled = false;
//過濾器處理結(jié)果
boolean result = false;
//從停止的位置反向執(zhí)行過濾器
for (int j = i; j >= 0; --j) {
if (!(this.commands[j] instanceof Filter)) continue;
try {
//執(zhí)行過濾器的postprocess方法,并傳入異常
result = ((Filter)this.commands[j]).postprocess(context, saveException);
if (result) {
handled = true;
}
}
catch (Exception e)
{
}
}
//判斷過濾器的處理狀態(tài) 如果過濾器處理不了就拋給上層處理
if ((saveException != null) && (!(handled))) {
throw saveException;
}
return saveResult;
}
Command[] getCommands()
{
return this.commands;
}
}
舉個(gè)栗子
//聲明要執(zhí)行的命令
class FirstStep implements Command{
public boolean execute(Context paramContext){
System.out.println("執(zhí)行第一步");
return false;
}
}
class SecondStep implements Command{
public boolean execute(Context paramContext){
System.out.println("執(zhí)行第二步");
return false;
}
}
class ThirdStep implements Command{
public boolean execute(Context paramContext){
System.out.println("執(zhí)行第三步");
return false;
}
}
//聲明攔截器 可選
class SetBeforeFilter implements Filter {
public boolean execute(Context paramContext){
System.out.println("執(zhí)行前");
return false;//return false為繼續(xù)往下執(zhí)行
}
//后置執(zhí)行方法稳衬,所有command執(zhí)行完后會(huì)反過來執(zhí)行postprocess
public boolean postprocess(Context paramContext, Exception paramException){
//這里可以處理異常弓摘,如果paramExeception 部位空的話
System.out.println("異常信息"+paramException);
System.out.println("后置執(zhí)行");
return true; //返回是否處理进鸠,如果異常信息不為空并且返回false程序會(huì)拋出異常
}
}
//構(gòu)建執(zhí)行鏈
注意:鏈?zhǔn)前错樞驁?zhí)行的
class StepChain extends ChainBase{
//這里通過構(gòu)造器初始化執(zhí)行鏈
public StepChain(){
addCommand(new SetBeforeFilter());
addCommand(new FirstStep());
addCommand(new SecondStep());
addCommand(new ThirdStep());
}
}
//測試
class Test{
public static void main(String[] args) throws Exception {
//上下文,用于多個(gè)command之間的數(shù)據(jù)傳遞
Context context = new ContextBase();
ChainBase chain = new StepChain();
chain.execute(context);
}
}
輸出
- 執(zhí)行前
- 執(zhí)行第一步
- 執(zhí)行第二步
- 執(zhí)行第三步
- 異常信息null
- 后置執(zhí)行
適用范圍
適合復(fù)雜的業(yè)務(wù)流程并且業(yè)務(wù)流程后續(xù)會(huì)增加或變化的情況
設(shè)計(jì)模式分析
commons-chain 主要使用了責(zé)任鏈模式
Command 類在實(shí)際使用的時(shí)候也可以通過模板模式拓展
責(zé)任鏈模式的優(yōu)點(diǎn)
責(zé)任鏈模式屏蔽了處理過程穷吮,鏈中的每個(gè)類只需要處理好自己的事情芙沥,處理完后最終會(huì)返回一個(gè)處理結(jié)果(當(dāng)然也可以不做
任何處理),作為調(diào)用者可以不用知道到底是需要誰來處理的封断,這是責(zé)任鏈模式的核心,同時(shí)責(zé)任鏈模式也可以作為一種補(bǔ)救模式來使用舶担。舉個(gè)常用的例子坡疼,如常用的Struts2的攔截器,你可以通過簡單的配置文件就可以將攔截器插入請求處理鏈中處理一些業(yè)務(wù)邏輯
有人可能會(huì)問這種方式和分成多個(gè)方法然后在一個(gè)方法中調(diào)用有什么區(qū)別嗎衣陶?
首先區(qū)別還是有的,Java是一門面向?qū)ο蟮木幊陶Z言柄瑰,都是在大多數(shù)情況下我們的業(yè)務(wù)處理都是一個(gè)service一竿子捅到底,這個(gè)明顯就是用面向?qū)ο蟮恼Z言做著面向過程的事剪况,一個(gè)service類處理所有的業(yè)務(wù)邏輯那么這個(gè)類肯定非常大教沾,代碼也非常長,維護(hù)起來也不好維護(hù)译断,一個(gè)有幾百行的業(yè)務(wù)方法維護(hù)起來通常要小心翼翼授翻,因?yàn)橐徊恍⌒母亩嗔嘶騽h錯(cuò)某行代碼那鍋肯定甩不掉了,有些沒有經(jīng)驗(yàn)程序員寫的方法可能都是public這種情況下一個(gè)類就會(huì)暴露過多的方法造成各個(gè)類之間的引用混亂镐作,如果你想要?jiǎng)h除一個(gè)public修飾的方法你需要考慮是否有其他類引用這個(gè)方法藏姐,這些坑前面的先驅(qū)都已經(jīng)踩過了,所以才有了設(shè)計(jì)模式
推薦下個(gè)人blog+bbs www.youngboy.vip