JAVA設計模式學習20——責任鏈模式

文章來源:http://www.tuicool.com/articles/RJvARj

責任鏈(Chain of Responsibility)模式 :責任鏈模式是對象的行爲模式。使多個對象都有機會處理請求,從而避免請求的發送者和接受者直接的耦合關係。將這些對象連成一條鏈,沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。責任鏈模式強調的是每一個對象及其對下家的引用來組成一條鏈,利用這種方式將發送者和接收者解耦,類圖如下:


通過上圖可以看出責任鏈模式有兩個角色:
抽象處理者(Handler)角色 :定義一個請求的接口。如果需要可以定義個一個方法用來設定和返回下家對象的引用。
具體處理者(ConcreteHandler)角色 :如果可以處理就處理請求,如果不能處理,就把請求傳給下家,讓下家處理。也就是說它處理自己能處理的請求且可以訪問它的下家。
上述模式的測試代碼如下:
package chainOfResp;
/**
 * 
 *作者:alaric
 *時間:2013-8-17上午11:01:58
 *描述:抽象處理角色
 */
public abstract class Handler {

  protected Handler successor;
  /**
   * 
   *作者:alaric
   *時間:2013-8-17上午11:04:22
   *描述:處理方法
   */
  public abstract void handlerRequest(String condition);
  
  
  public Handler getSuccessor() {
    return successor;
  }
  public void setSuccessor(Handler successor) {
    this.successor = successor;
  }	
  
}
 
package chainOfResp;
/**
 * 
 *作者:alaric
 *時間:2013-8-17上午11:25:54
 *描述:具體處理角色
 */
public class ConcreteHandler1 extends Handler {

  @Override
  public void handlerRequest(String condition) {
    // 如果是自己的責任,就自己處理,負責傳給下家處理
    if(condition.equals("ConcreteHandler1")){
      System.out.println( "ConcreteHandler1 handled ");
      return ;
    }else{
      System.out.println( "ConcreteHandler1 passed ");
      getSuccessor().handlerRequest(condition);
    }
  }

}
 
package chainOfResp;
/**
 * 
 *作者:alaric
 *時間:2013-8-17上午11:25:54
 *描述:具體處理角色
 */
public class ConcreteHandler2 extends Handler {
  
  @Override
  public void handlerRequest(String condition) {
    // 如果是自己的責任,就自己處理,負責傳給下家處理
    if(condition.equals("ConcreteHandler2")){
      System.out.println( "ConcreteHandler2 handled ");
      return ;
    }else{
      System.out.println( "ConcreteHandler2 passed ");
      getSuccessor().handlerRequest(condition);
    }
  }

}
 
package chainOfResp;
/**
 * 
 *作者:alaric
 *時間:2013-8-17上午11:25:54
 *描述:具體處理角色
 */
public class ConcreteHandlerN extends Handler {

  /**
   * 這裏假設n是鏈的最後一個節點必須處理掉
   * 在實際情況下,可能出現環,或者是樹形,
   * 這裏並不一定是最後一個節點。
   * 
   */
  @Override
  public void handlerRequest(String condition) {

    System.out.println( "ConcreteHandlerN handled");
    
  }

}
 
package chainOfResp;
/**
 * 
 *作者:alaric
 *時間:2013-8-17上午10:59:06
 *描述:測試類
 */
public class Client {

  /**
   *作者:alaric
   *時間:2013-8-17上午10:58:58
   *描述:
   */
  public static void main(String[] args) {
  
    Handler handler1 = new ConcreteHandler1();
    Handler handler2 = new ConcreteHandler2();
    Handler handlern = new ConcreteHandlerN();
    
    //鏈起來
    handler1.setSuccessor(handler2);
    handler2.setSuccessor(handlern);
    
    //假設這個請求是ConcreteHandler2的責任
    handler1.handlerRequest("ConcreteHandler2");
    
    
  }

}
 
舉這樣一個例子,在玩具工廠的生產車間,流水線就是一條責任鏈,假如一個玩具飛機有外殼裝配員,引擎裝配員,螺旋槳裝配員,模型包裝員組成。當這個物件飛機流到誰那裏,誰就負責安裝他負責的這一部分,這部分安裝完成後流到下一個環節,知道所有環境完成。這個是一生成的責任鏈。還有一個質量檢測鏈,質量檢測也分多部,外殼檢測,引擎檢測,螺旋槳檢測,包裝檢測。當產品留到檢測員那裏檢測自己負責的那一塊,如果有問題直接拎出來,如果沒問題則傳給下一個檢測員,直到所有檢測完成。這兩個都是責任鏈,但是區別是,生成責任鏈每個人都會處理,並處理一部分;而質量檢測責任鏈經過判斷,要麼處理掉,要麼不處理流下去。這就是責任鏈的兩種分類,後一種叫做純的責任鏈,前一種叫做不純的責任鏈,純的責任鏈在實際應用中很少存在,常見的爲不純的責任鏈,上面的模型是模擬純的責任鏈來處理的。
 
責任鏈模式在現實中使用的很多,常見的就是OA系統中的工作流。 在java中的實際應用有Servlet中的過濾器(Filter),Struts2的攔截器(Interceptor)。Struts2本身在Servlet中也是以Filter的形式出現的,所以Struts2的結構圖中,也可以明顯看出Filter和Interceptor這兩條鏈的存在。

  可以看出它們每個節點都可以做一些事情,所以不算一個純的責任鏈。
在上面提到了OA系統,那麼我們再模擬一下OA系統中請假審批流程,假如員工直接上司爲小組長,小組長直接上司項目經理,項目經理直接上司部門經理,部門經理直接上司總經理。公司規定請假審批如下:
請假時間爲t,時間單位day,簡寫d:
t<  0.5d,小組長審批;
t>=0.5d,t<2,項目經理審批;
t>=2,t<5部門經理審批;
t>=5總經理審批;
審批時序圖如下:

用代碼描述:  
package chainOfResp.example;
/**
 * 
 *作者:alaric
 *時間:2013-8-17下午1:02:51
 *描述:審批處理抽象類
 */
public abstract class Handler {

  protected Handler handler;

  /**
   * 
   *作者:alaric
   *時間:2013-8-17下午1:07:40
   *描述:審批
   */
  public abstract boolean approve(double day);
  
  public Handler getHandler() {
    return handler;
  }
  public void setHandler(Handler handler) {
    this.handler = handler;
  }
  
}
 
package chainOfResp.example;


public class GroupLeader extends Handler {

  @Override
  public boolean approve(double day) {
    if(day<0.5){
      System.out.println("小組長審批通過");
      return true;
    }else {
      System.out.println("小組長傳給了他的上司");
      return getHandler().approve(day);
    }
  }


}
 
package chainOfResp.example;


public class ProjectManager extends Handler {

  @Override
  public boolean approve(double day) {
    if(day<2){
      System.out.println("項目經理審批通過");
      return true;
    }else {
      System.out.println("項目經理傳給了他的上司");
      return getHandler().approve(day);
    }
  }


}
 
package chainOfResp.example;


public class DepartmentManager extends Handler {

  @Override
  public boolean approve(double day) {
    if(day<5){
      System.out.println("部門經理審批通過");
      return true;
    }else {
      System.out.println("部門經理傳給了他的上司");
      return getHandler().approve(day);
    }
  }


}
 
package chainOfResp.example;


public class CEO extends Handler {

  @Override
  public boolean approve(double day) {
      System.out.println("部門經理審批通過");
      return true;
    
  }

}
 
package chainOfResp.example;
/**
 * 
 *作者:alaric
 *時間:2013-8-17下午12:54:51
 *描述:測試類,首先來創建責任鏈,然後發出請求模擬員工來請假
 */
public class Client {

  /**
   *作者:alaric
   *時間:2013-8-17下午12:54:44
   *描述:
   */
  public static void main(String[] args) {

    //創建節點
    GroupLeader gl = new GroupLeader();
    ProjectManager pm = new ProjectManager();
    DepartmentManager dm = new DepartmentManager();
    CEO ceo = new CEO();
    //建立責任鏈
    gl.setHandler(pm);
    pm.setHandler(dm);
    dm.setHandler(ceo);
    
    //向小組長髮出申請,請求審批4天的假期
    gl.approve(4D);
    

  }

}
  運行結果:
小組長傳給了他的上司
項目經理傳給了他的上司
部門經理審批通過
 
這裏模擬的是一個理想的狀態,所以是一個純的責任鏈;在實際當中,可能小組長簽字,項目經理簽字...一堆的簽字,而不是不參與請求的處理。
責任鏈模式的優點是調用者不需知道具體誰來處理請求,也不知道鏈的具體結構,降低了節點域節點的耦合度;可在運行時動態修改鏈中的對象職責,增強了給對象指派職責的靈活性;缺點是沒有明確的接收者,可能傳到鏈的最後,也沒得到正確的處理。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章