<input id="ohw05"></input>
  • <table id="ohw05"><menu id="ohw05"></menu></table>
  • <var id="ohw05"></var>
  • <code id="ohw05"><cite id="ohw05"></cite></code>
    <label id="ohw05"></label>
    <var id="ohw05"></var>
  • 設計模式:如何優雅地使用責任鏈模式

    責任鏈模式(Chain of Responsibility Pattern)在《Head First設計模式》一書中被稱為“剩下的模式”,其實使用也是蠻多的。最近在學習Netty的過程中用到了責任鏈模式,在此反過頭來重溫一下責任鏈模式。

    當你想要讓一個以上的對象有機會能夠處理某個請求的時候,就使用責任鏈模式。

    一、場景

    借用《Head First設計模式》書中的典型場景:需要處理四種類型的電子郵件,第一種類型是粉絲寄來的信,表示他們喜歡新推出的游戲;第二種類型是父母寄來的信,他們抱怨孩子總是沉迷游戲而忘記做作業;第三種類型是店家希望在其他地方也擺放糖果機;第四種類型是垃圾郵件。現在已經可以根據郵件內容確定收到的郵件屬于哪種類型,需要設計一個程序來處理這些郵件。

    Talk is cheap. Show me the code.直接用代碼來說話吧。

    用枚舉來定義四種類型的郵件:

    public enum EmailEnum {
        SPAM_EMAIL(1, "Spam_Email"),
        FAN_EMAIL(2, "Fan_Email"),
        COMPLAINT_EMAIL(3, "Complaint_Email"),
        NEW_LOC_EMAIL(4, "New_Loc_Email");
    
        private Integer code;
        private String desc;
    
        EmailEnum(Integer code, String desc) {
            this.code = code;
            this.desc = desc;
        }
    
        public Integer getCode() {
            return code;
        }
    
        public String getDesc() {
            return desc;
        }
    }
    

    假設郵件有兩個屬性:郵件類型和郵件內容,定義郵件:

    public class Email {
        int type;
        String content;
    
        public Email(int type, String content) {
            this.type = type;
            this.content = content;
        }
    
        public int getType() {
            return type;
        }
    
        public String getContent() {
            return content;
        }
    }
    

    二、不使用責任鏈模式

    如果不采用責任鏈模式?使用EmailHandler這個類來統一處理上述四種郵件,程序是這樣子的:

    public class EmailHandler {
    
        public void handleEmai(Email email) {
            if (EmailEnum.SPAM_EMAIL.getCode().equals(email.getType())) {
                // 處理垃圾郵件
                handleSpamEmail(email);
            }
            if (EmailEnum.FAN_EMAIL.getCode().equals(email.getType())) {
                // 處理粉絲郵件
                handleFanEmail(email);
            }
            if (EmailEnum.COMPLAINT_EMAIL.getCode().equals(email.getType())) {
                // 處理抱怨郵件
                handleComplaintEmail(email);
            } else {
                // 處理新增郵件
                handleNewLocEmail(email);
            }
        }
    
        private void handleNewLocEmail(Email email) {
            System.out.println("handleNewLocEmail...");
            // 處理代碼省略
        }
    
        private void handleComplaintEmail(Email email) {
            System.out.println("handleComplaintEmail...");
            // 處理代碼省略
        }
    
        private void handleFanEmail(Email email) {
            System.out.println("handleFanEmail...");
            // 處理代碼省略
        }
    
        public void handleSpamEmail(Email email) {
            System.out.println("handleSpamEmail...");
            // 處理代碼省略
        }
    }
    

    這個類雖然強大,但是是不夠優雅的:

    (1)EmailHandler類較為龐大,各種類型郵件的處理都集中在一個類中,違反了“單一職責原則”。

    (2)如果之后增加新的郵件類型、刪除某一種郵件類型,或者有其他新功能的拓展,都必須修改源代碼并進行嚴格測試,違反了“開閉原則”。

    開放-關閉原則:類應該對擴展開放,對修改關閉。

    三、使用責任鏈模式

    如何進行改進呢?那就是使用責任鏈模式,為某個請求創建一個對象鏈。每個對象按照順序檢查這個請求,并對其處理,或者將它傳遞給鏈中的下一個對象。在本例中,當收到電子郵件的時候,先進入第一個處理器SpamHandler,如果SpamHandler無法處理,就將它傳給FanHandler,以此類推...

    本例使用責任鏈模式的結構圖如圖所示:
    UML 類圖

    Handler是一個抽象的處理器,是一個抽象類。抽象類中定義了一個抽象處理器的對象successor,通過該引用,可以形成一條責任鏈。抽象類中還定義了抽象處理請求的的方法handleRequest()。代碼如下:

    public abstract class Handler {
        protected Handler successor;
    
        public void setSuccessor(Handler successor) {
            this.successor = successor;
        }
    
        public abstract void handleRequest(Email email);
    }
    

    SpamHandler、FanHandler、ComplaintHandler和NewLocHandler是具體的處理器,繼承抽象類Handler,用來處理具體的郵件請求。處理細節:處理之前要進行類型的判斷,看是否能夠處理該請求,如果可以處理就處理,否則就轉發給后繼的處理器去處理。代碼如下:

    SpamHandler

    public class SpamHandler extends Handler{
        @Override
        public void handleRequest(Email email) {
            if (EmailEnum.SPAM_EMAIL.getCode().equals(email.getType())) {
                //處理請求
                System.out.println("SpamHandler handleRequest...");
            }
            else {
                this.successor.handleRequest(email);  //轉發請求
            }
        }
    }
    

    FanHandler

    public class FanHandler extends Handler{
        @Override
        public void handleRequest(Email email) {
            if (EmailEnum.FAN_EMAIL.getCode().equals(email.getType())) {
                //處理請求
                System.out.println("FanHandler handleRequest...");
            }
            else {
                this.successor.handleRequest(email);  //轉發請求
            }
        }
    }
    

    ComplaintHandler

    public class ComplaintHandler extends Handler{
        @Override
        public void handleRequest(Email email) {
            if (EmailEnum.COMPLAINT_EMAIL.getCode().equals(email.getType())) {
                //處理請求
                System.out.println("ComplaintHandler handleRequest...");
            }
            else {
                this.successor.handleRequest(email);  //轉發請求
            }
        }
    }
    

    NewLocHandler

    public class NewLocHandler extends Handler{
        @Override
        public void handleRequest(Email email) {
            if (EmailEnum.NEW_LOC_EMAIL.getCode().equals(email.getType())) {
                //處理請求
                System.out.println("NewLocHandler handleRequest...");
            }
            else {
                this.successor.handleRequest(email);  //轉發請求
            }
        }
    }
    

    需要注意的是,責任鏈模式并不創建責任鏈,責任鏈的創建工作必須由系統的其他部分來完成,一般是在使用該責任鏈的客戶端中創建責任鏈。責任鏈模式降低了請求的發送端和接收端之間的耦合,使多個對象都有機會處理這個請求。下面編寫測試類進行測試:

    public class Test {
        public static void main(String[] args) {
            // 創建郵件處理請求
            Email email1 = new Email(1,"aaa");
            Email email2 = new Email(2,"bbb");
            Email email3 = new Email(3,"ccc");
            Email email4 = new Email(4,"ddd");
            // 創建Handler
            SpamHandler handler1 = new SpamHandler();
            FanHandler handler2 = new FanHandler();
            ComplaintHandler handler3 = new ComplaintHandler();
            NewLocHandler handler4 = new NewLocHandler();
            // 創建責任鏈
            handler1.setSuccessor(handler2);
            handler2.setSuccessor(handler3);
            handler3.setSuccessor(handler4);
            // 處理請求
            handler1.handleRequest(email1);
            handler1.handleRequest(email2);
            handler1.handleRequest(email3);
            handler1.handleRequest(email4);
        }
    }
    

    在代碼中創建四種類型的郵件用于處理,創建了四種不同的處理器(SpamHandler、FanHandler、ComplaintHandler、NewLocHandler),形成“handler1 -> handler2 -> handler3 -> handler4”的責任鏈,使用這條責任鏈處理四種類型的郵件。運行結構如下:

    這樣處理之后,明顯使得請求發送者和接受者解耦;每個實現類都有自己明確且獨一無二的職責;如果增加一個類型,只需要再增加一個具體類去繼承Handler,書寫自己的處理邏輯,在責任鏈中進行添加;如果刪除某種類型的,只需要在構建責任鏈的時候,把它刪除就可以了,實現動態增加或者刪除責任,符合設計模式的原則。

    四、總結

    責任鏈模式通過建立一條鏈來組織請求的處理者,請求將沿著鏈進行傳遞,請求發送者無須知道請求在何時、何處以及如何被處理,實現了請求發送者與處理者的解耦。在軟件開發中,如果遇到有多個對象可以處理同一請求時可以應用責任鏈模式,例如在Web應用開發中創建一個過濾器鏈來對請求數據進行過濾,在工作流系統中實現公文的分級審批等等,使用責任鏈模式可以較好地解決此類問題。

    posted @ 2020-07-25 19:16  James_Shangguan  閱讀(808)  評論(0編輯  收藏  舉報
    国产美女a做受大片观看