設計模式之責任鏈模式

責任鏈模式

0x01.定義與類型

  • 定義:爲了不請求發送者與多個請求處理者耦合在一塊兒,將全部請求的處理者經過前一對象記住其下一個對象的引用而連成一條鏈;當有請求發生時,可將請求沿着這條鏈傳遞,直到有對象處理它爲止。
  • 類型:行爲型
  • UML類圖

chain-of-responsibility1.png

  • java實現
/**
 * 抽象處理類
 */
public abstract class Handler {

    //責任鏈下一個節點
    protected Handler successor;

    /**
     * 處理請求
     */
    public abstract void handlerRequest(Integer count);

    public Handler getSuccessor() {
        return successor;
    }

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
}

/**
 * 實際責任鏈處理器1
 */
public class ConcreteHandler1 extends Handler {
    @Override
    public void handlerRequest(Integer count) {
        System.out.println("goto ConcreteHandler1");
        if (count <= 0) {
            System.out.println("ConcreteHandler1 process.");
        } else if (getSuccessor() != null) {
            getSuccessor().handlerRequest(count);
        }
    }
}

/**
 * 實際責任鏈處理器2
 */
public class ConcreteHandler2 extends Handler {
    @Override
    public void handlerRequest(Integer count) {
        System.out.println("goto ConcreteHandler2");
        if (count > 0) {
            System.out.println("ConcreteHandler2 process.");
        } else if (getSuccessor() != null) {
            getSuccessor().handlerRequest(count);
        }
    }
}
  • 測試與應用
/**
 * 測試與應用
 */
public class Test {

    public static void main(String[] args) {
        //建立責任鏈
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();

        //組裝
        handler1.setSuccessor(handler2);

        //處理
        handler1.handlerRequest(1);
    }
}
  • 輸入結果
goto ConcreteHandler1
goto ConcreteHandler2
ConcreteHandler2 process.
  • 角色介紹html

    • 抽象處理者(Handler)角色:定義出一個處理請求的接口。若是須要,接口能夠定義出一個方法以設定和返回對下家的引用。這個角色一般由一個Java抽象類或者Java接口實現。上圖中Handler類的聚合關係給出了具體子類對下家的引用,抽象方法handleRequest()規範了子類處理請求的操做。
    • 具體處理者(ConcreteHandler)角色:具體處理者接到請求後,能夠選擇將請求處理掉,或者將請求傳給下家。因爲具體處理者持有對下家的引用,所以,若是須要,具體處理者能夠訪問下家。

0x02.適用場景

  • 一個請求的處理須要多個對象當中的一個或幾個協做處理
  • if else比較多的狀況,能夠考慮是否合適

0x03.優缺點

1.優勢

  • 下降了對象之間的耦合度。該模式使得一個對象無須知道究竟是哪個對象處理其請求以及鏈的結構,發送者和接收者也無須擁有對方的明確信息。
  • 加強了系統的可擴展性。能夠根據須要增長新的請求處理類,知足開閉原則。
  • 加強了給對象指派職責的靈活性。當工做流程發生變化,能夠動態地改變鏈內的成員或者調動它們的次序,也可動態地新增或者刪除責任。
  • 責任鏈簡化了對象之間的鏈接。每一個對象只需保持一個指向其後繼者的引用,不需保持其餘全部處理者的引用,這避免了使用衆多的 if 或者 if···else 語句。
  • 責任分擔。每一個類只須要處理本身該處理的工做,不應處理的傳遞給下一個對象完成,明確各種的責任範圍,符合類的單一職責原則。

2.缺點

  • 不能保證每一個請求必定被處理。因爲一個請求沒有明確的接收者,因此不能保證它必定會被處理,該請求可能一直傳到鏈的末端都得不處處理。
  • 對比較長的職責鏈,請求的處理可能涉及多個處理對象,系統性能將受到必定影響。
  • 職責鏈創建的合理性要靠客戶端來保證,增長了客戶端的複雜性,可能會因爲職責鏈的錯誤設置而致使系統出錯,如可能會形成循環調用。

0x04.責任鏈模式樣例

你去買東西想要申請折扣,每一個level的人只能批准本身範圍內的,批准不了的只能上報給leader.
  • java代碼
/**
 * 價格處理人, 負責處理客戶的責任申請
 */
public abstract class PriceHandler {

    /**
     * 直接後繼, 用於處理請求
     */
    protected PriceHandler successor;

    public void setSuccessor(PriceHandler successor) {
        this.successor = successor;
    }

    /**
     * 處理折扣申請
     */
    public abstract void processDiscount(float discount);

}

//下面是責任鏈的各個節點
public class CEO extends PriceHandler {

    @Override
    public void processDiscount(float discount) {

        if (discount <= 0.55) {
            System.out.format("%s approved: %.2f%n", this.getClass().getName(), discount);
        } else {
            System.out.format("%s refused: %.2f%n", this.getClass().getName(), discount);
        }
    }

}

public class Director extends PriceHandler {

    @Override
    public void processDiscount(float discount) {

        if (discount <= 0.35) {
            System.out.format("%s approved: %.2f%n", this.getClass().getName(), discount);
        } else {
            successor.processDiscount(discount);
        }
    }

}

public class Lead extends PriceHandler {

    @Override
    public void processDiscount(float discount) {

        if (discount <= 0.15) {
            System.out.format("%s approved: %.2f%n", this.getClass().getName(), discount);
        } else {
            successor.processDiscount(discount);
        }
    }

}

public class Manager extends PriceHandler {

    @Override
    public void processDiscount(float discount) {

        if (discount <= 0.2) {
            System.out.format("%s approved: %.2f%n", this.getClass().getName(), discount);
        } else {
            successor.processDiscount(discount);
        }
    }

}

public class Sales extends PriceHandler {

    @Override
    public void processDiscount(float discount) {

        if (discount <= 0.05) {
            System.out.format("%s approved: %.2f%n", this.getClass().getName(), discount);
        } else {
            successor.processDiscount(discount);
        }
    }

}

public class VicePresident extends PriceHandler {

    @Override
    public void processDiscount(float discount) {

        if (discount <= 0.45) {
            System.out.format("%s approved: %.2f%n", this.getClass().getName(), discount);
        } else {
            successor.processDiscount(discount);
        }
    }

}

//責任鏈拼裝工廠
public class PriceHandlerFactory {

    /**
     * 獲取PriceHandler 對象
     * @return PriceHandler
     */
    public static PriceHandler createPriceHandler() {

        PriceHandler sales = new Sales();
        PriceHandler lead = new Lead();
        PriceHandler manager = new Manager();
        PriceHandler director = new Director();
        PriceHandler vp = new VicePresident();
        PriceHandler ceo = new CEO();

        sales.setSuccessor(lead);
        lead.setSuccessor(manager);
        manager.setSuccessor(director);
        director.setSuccessor(vp);
        vp.setSuccessor(ceo);
        return sales;
    }
}
  • 客戶類(應用類)
/**
 * 客戶, 申請折扣
 */
public class Customer {

    private PriceHandler priceHandler;

    public void setPriceHandler(PriceHandler priceHandler) {
        this.priceHandler = priceHandler;
    }

    public void requestDiscount (float discount) {
        priceHandler.processDiscount(discount);
    }


    public static void main(String[] args) {
        Customer customer = new Customer();
        customer.setPriceHandler(PriceHandlerFactory.createPriceHandler());

        Random random = new Random();

        for (int i = 0; i < 10; i++) {
            System.out.print((i + 1) + ":");
            customer.requestDiscount(random.nextFloat());
        }

    }
}
  • 運行結果
1:org.ko.cor.demo1.handler.CEO approved: 0.46
2:org.ko.cor.demo1.handler.CEO refused: 0.55
3:org.ko.cor.demo1.handler.CEO refused: 0.61
4:org.ko.cor.demo1.handler.CEO approved: 0.53
5:org.ko.cor.demo1.handler.CEO refused: 0.83
6:org.ko.cor.demo1.handler.CEO refused: 0.72
7:org.ko.cor.demo1.handler.CEO refused: 0.69
8:org.ko.cor.demo1.handler.Director approved: 0.28
9:org.ko.cor.demo1.handler.Lead approved: 0.07
10:org.ko.cor.demo1.handler.CEO refused: 0.93
  • UML類圖

chain-of-responsibility2.png

0x05.相關的設計模式

  • 責任鏈模式和狀態模式java

    • 責任鏈模式各個對象並不指定下一個處理的對象是誰
    • 狀態模式:讓每一個狀態對象知道下一個對象是誰

0x06.源碼中的責任鏈模式

  • Servlet.FilterChainr#doFilter
  • SpringSecurity

0x07.源碼地址

0x08.推薦閱讀

相關文章
相關標籤/搜索