Apache commons-chain 核心分析

類和接口關(guān)系分析

class.jpg

接口定義

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末该贾,一起剝皮案震驚了整個(gè)濱河市羔杨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杨蛋,老刑警劉巖兜材,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異逞力,居然都是意外死亡曙寡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門寇荧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來举庶,“玉大人,你說我怎么就攤上這事揩抡』Ы模” “怎么了镀琉?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蕊唐。 經(jīng)常有香客問我屋摔,道長,這世上最難降的妖魔是什么替梨? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任钓试,我火速辦了婚禮,結(jié)果婚禮上副瀑,老公的妹妹穿的比我還像新娘弓熏。我一直安慰自己,他們只是感情好俗扇,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布硝烂。 她就那樣靜靜地躺著,像睡著了一般铜幽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上串稀,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天除抛,我揣著相機(jī)與錄音,去河邊找鬼母截。 笑死到忽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的清寇。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼捶箱!你這毒婦竟也來了酿矢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤盔夜,失蹤者是張志新(化名)和其女友劉穎负饲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喂链,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡返十,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椭微。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洞坑。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蝇率,靈堂內(nèi)的尸體忽然破棺而出迟杂,到底是詐尸還是另有隱情刽沾,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布逢慌,位于F島的核電站悠轩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏攻泼。R本人自食惡果不足惜火架,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忙菠。 院中可真熱鬧何鸡,春花似錦、人聲如沸牛欢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽傍睹。三九已至隔盛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拾稳,已是汗流浹背吮炕。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留访得,地道東北人龙亲。 一個(gè)月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像悍抑,于是被迫代替她去往敵國和親鳄炉。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容