设计模式:责任链模式(Chain of Responsibility, CoR)

来源:互联网 发布:sql不同数据类型运算 编辑:程序博客网 时间:2024/05/20 12:48

目的:

      使多个物件都有机会处理请求,以避免请求的发送者与接收者之间的耦合关系,将这些物件组合为一个链,并沿着这个链传递该请求,直到有物件处理它为止。

    has a chance to handle the request. 实际上是把结构化的

if(/* 符合请求条件一 */)
    // 执行请求一
else if(/* 符合请求条件二 */)
    // 执行请求二
else
    // 执行预设请求或显示讯息

进行了OO转换,对switch也一样

先用一个例子来说明使用if...else的方式来处理请求:

  • IHandler.java
public interface IHandler {    public void handle(); }  


  • SymbolHandler.java
public class SymbolHandler implements IHandler {     public void handle() {        System.out.println("Symbol has been handled");     } }  


  • CharacterHandler.java
public class CharacterHandler implements IHandler {     public void handle() {        System.out.println("Character has been handled");     } }  


  • NumberHandler.java
public class NumberHandler implements IHandler {     public void handle() {        System.out.println("Number has been handled");     } } 


  • Application.java
import java.io.*; public class Application {    public void run() throws Exception {        System.out.print("Press any key then return: ");        char c = (char) System.in.read();        IHandler handler = null;        if (Character.isLetter(c)) {         handler = new CharacterHandler();        }       else if (Character.isDigit(c)) {          handler = new NumberHandler();        }       else {          handler = new SymbolHandler();        }       handler.handle();    }    public static void main(String[] args)                            throws IOException {          Application app = new Application();          app.run();    } } 


这是一个很简单的程式,可以判定您所输入的是数字、字元或是符号,如果将之以物件的方式来组织物件之间的职责,可以将程式改写如下:
  • Handler.java
public class Handler {     private Handler successor;    public void setSuccessor(Handler successor) {         this.successor = successor;     }    public Handler getSuccessor() {         return successor;     }    public void handleRequest(char c) {         if(successor != null)             successor.handleRequest(c);     } }  


  • NumberHandler.java
public class NumberHandler extends Handler {     public void handleRequest(char c) {         if(Character.isDigit(c)) {             System.out.println("Number has been handled");         }         else {            getSuccessor().handleRequest(c);         }    } }  


  • CharacterHandler.java
public class CharacterHandler extends Handler {     public void handleRequest(char c) {         if(Character.isLetter(c)) {             System.out.println("Character has been handled");         }         else {            getSuccessor().handleRequest(c);         }    } }  


  • SymbolHandler.java
public class SymbolHandler extends Handler {     public void handleRequest(char c) {         System.out.println("Symbol has been handled");     } }  


  • Application.java
import java.io.*; public class Application {    public static void main(String[] args)                                  throws IOException {         Handler numberHandler = new NumberHandler();         Handler characterHandler = new CharacterHandler();         Handler symbolHandler = new SymbolHandler();         numberHandler.setSuccessor(characterHandler);         characterHandler.setSuccessor(symbolHandler);         System.out.print("Press any key then return: ");         char c = (char)System.in.read();         numberHandler.handleRequest(c);     } } 



在组织物件之间的职责时,通常是从细粒度至粗粒度的方式来组织,从特殊到抽象化,就像程式中将数字视为字元的特殊化,字元又为符号的特殊化。

Chain of Responsibility的 UML 结构图如下所示:
Chain of Responsibility

从物件执行请求的时间来看,其运作是很简单的职责传递而已,如下:
Chain of Responsibility

以上所举的例子在请求上是很简单的,只是比对输入的型态,在更一般的情况下,可以将请求包装为一个物件,并提供getType()之间的方法,以让Chain of Responsibility中的物件进行比对,例如:
  • Request.java
public class Request{   private String type;     public Request(String type) { this.type=type; }  public String getType() { return type; }  public void execute(){             // 执行请求   } } 


在Gof的书中所举的例子为辅助说明系统,在一个介面中希望使用者一定可以得到相关的说明主题,如果子元件有说明的话,就显示相关说明,否则的话就转发给包括它的容器元件或父元件,以保证使用者的辅助说明请求一定可以得到回应。

CoR的优点:
因为无法预知来自外界(客户端)的请求是属于哪种类型,每个类如果碰到它不能处理的请求只要放弃就可以。

缺点是效率低,因为一个请求的完成可能要遍历到最后才可能完成,当然也可以用树的概念优化。 在Java AWT1.0中,对于鼠标按键事情的处理就是使用CoR,到Java.1.1以后,就使用Observer代替CoR

扩展性差,因为在CoR中,一定要有一个统一的接口Handler.局限性就在这里。

与Command模式区别:

Command 模式需要事先协商客户端和服务器端的调用关系,比如 1 代表 start 2 代表 move 等,这些 都是封装在 request 中,到达服务器端再分解。

CoR 模式就无需这种事先约定,服务器端可以使用 CoR 模式进行客户端请求的猜测,一个个猜测 试验。

体会:

CoR很类似于科学理论的研究过程,猜想,验证,不行,再猜想,在验证,只不过把猜想的过程连接起来,形成chain。

必须确定地构建CoR

对象间耦合是Data ,DD设计