設計模式 — 責任鏈模式


1.1 簡介

  • 責任鏈模式為請求創建一個接收者對象鏈,每個接收者都包含對另一個接收者的引用,如果一個對象不能處理該請求,那么它會把請求傳給下一個接收者,依此類推
  • 責任鏈模式避免了請求的發送者和接收者耦合在一起,讓多個對象都有可能接收請求,將這些對象連成一條鏈,並且沿着這條鏈傳遞請求,直到有對象處理它為止。

1.2 責任鏈模式優缺點

 優點

降低耦合度。它將請求的發送者和接收者解耦 
簡化了對象,使得對象不需要知道鏈的結構 
增強給對象指派職責的靈活性,允許動態地新增或者刪除責任鏈 
增加新的請求處理類方便

 缺點

不能保證請求一定被接收; 
系統性能將受到一定影響,調試時不方便,可能會造成循環調用

2 模式結構

 2.1 對象定義

  Handler(抽象處理者) : 定義一個處理請求的接口,提供對后續處理者的引用 
  ConcreteHandler(具體處理者) : 抽象處理者的子類,處理用戶請求,可選將請求處理掉還是傳給下家;在具體處理者中可以訪問鏈中下一個對象,以便請求的轉發

 2.2 類圖及設計

代碼詳解:

 抽象處理者

public abstract class Handler {

    protected Handler nextHandler; // 下一個責任鏈成員

    public Handler getNextHandler() {
        return nextHandler;
    }

    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    // 處理傳遞過來的時間
    public abstract void handleMessage(int type);
}

 具體處理者 
  在當前處理者對象無法處理時,將執行權傳給下一個處理者對象

public class ConcreteHandler1 extends Handler {

    @Override
    public void handleMessage(int type) {
        if (type == 1 || type == 3) {
            System.out.println("ConcreteHandler1解決了問題!");
        } else {
            System.out.println("ConcreteHandler1解決不了問題......");
            if (nextHandler != null) {
                nextHandler.handleMessage(type);
            } else {
                System.out.println("沒有人能處理這個消息");
            }
        }
    }
}

public class ConcreteHandler2 extends Handler {

    @Override
    public void handleMessage(int type) {
        if (type == 2 || type == 5) {
            System.out.println("ConcreteHandler2解決了問題!");
        } else {
            System.out.println("ConcreteHandler2解決不了問題......");
            if (nextHandler != null) {
                nextHandler.handleMessage(type);
            } else {
                System.out.println("沒有人能處理這個消息");
            }
        }
    }
}

public class ConcreteHandler3 extends Handler {

    @Override
    public void handleMessage(int type) {
        if (type == 4 || type == 6) {
            System.out.println("ConcreteHandler3解決了問題!");
        } else {
            System.out.println("ConcreteHandler3解決不了問題......");
            if (nextHandler != null) {
                nextHandler.handleMessage(type);
            } else {
                System.out.println("沒有人能處理這個消息");
            }
        }
    }
}

 Client 客戶端調用

        // 初始化責任鏈:handler1 -> handler2 -> handler3
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        Handler handler3 = new ConcreteHandler3();
        handler2.setNextHandler(handler3);
        handler1.setNextHandler(handler2);
        // 處理事件
        System.out.println("--------------Message1");
        handler1.handleMessage(1);
        System.out.println("--------------Message2");
        handler1.handleMessage(2);
        System.out.println("--------------Message3");
        handler1.handleMessage(4);
        System.out.println("--------------Message4");
        handler1.handleMessage(7);    

  從上述模式可以知道,當我們需要多個 ifelse 做邏輯判斷的時候,可以引入,從而提高代碼可維護性

 2.3 適用場景:

  • 有多個對象可以處理同一個請求,具體哪個對象處理該請求由運行時刻自動確定
  • 在不明確指定接收者的情況下,向多個對象中的某一個對象提交一個請求
  • 可動態指定一組對象的處理請求

 更詳細分析請看這篇:實際項目中運用責任鏈模式


 

另一個例子闡述:直接用馬士兵老師中的一個例子來講解

 我們有一個字符串String msg = ":):,<script>,敏感,被就業,網絡授課";我們希望應用以下三個規則對字符串進行過濾和諧處理:

  (1)將字符串中出現的"<>"符號替換成"[]"

  (2)處理字符串中的敏感信息,將被就業和諧成就業

  (3)將字符串中出現的":):"轉換成"^V^";

 字符串會依次運用這三條規則,對字符串進行處理,每個規則都有自己需要完成的責任和任務。

 第一步:定義封裝請求的類Request和封裝處理結果響應的類Response

//封裝請求的類Request
public class Request {
    String requestStr;

    public String getRequest() {
        return requestStr;
    }

    public void setRequest(String request) {
        this.requestStr = request;
    }
    
}
//封裝響應信息的類Response
public class Response {
    String responseStr;

    public String getResponse() {
        return responseStr;
    }

    public void setResponse(String response) {
        this.responseStr = response;
    }
    
}

第二步:定義具有過濾功能的接口Filter,具體的過濾規則需要實現該接口

/*
 * 定義接口Filter,具體的過濾規則需要實現這個接口,最后一個參數添加的意義是我們在Main函數中:
 * fc.doFilter(request, response,fc);執行這一步的時候可以按照規則鏈條一次使用三個過濾規則對字符串進行處理
 * 因為
 * 
 */
public interface Filter {
    void doFilter(Request request,Response response,FilterChain chain);
}

第三步:定義具體的過濾處理規則

規則一

package com.bjsxt.dp.filter;

//處理字符串中的HTML標記
public class HTMLFilter implements Filter {

    public void doFilter(Request request, Response response,FilterChain chain) {
        //將字符串中出現的"<>"符號替換成"[]"
        request.requestStr=request.requestStr
                .replace('<', '[').replace('>', ']')+
                //后面添加的是便於我們觀察代碼執行步驟的字符串
                "----HTMLFilter()";
        chain.doFilter(request, response,chain);
        response.responseStr+="---HTMLFilter()";
    }

}

規則二

package com.bjsxt.dp.filter;

//定義的過濾敏感字眼的過濾規則
public class SensitiveFilter implements Filter{

    public void doFilter(Request request, Response response,FilterChain chain) {
        //處理字符串中的敏感信息,將被就業和諧成就業
        request.requestStr=request.requestStr
                .replace("被就業", "就業").replace("敏感", "")+
                //后面添加的是便於我們觀察代碼執行步驟的字符串
                " ---sensitiveFilter()";
        chain.doFilter(request, response,chain);
        response.responseStr+="---sensitiveFilter()";
    }

}

  規則三

package com.bjsxt.dp.filter;

//定義FaceFilter
public class FaceFilter implements Filter {

    public void doFilter(Request request, Response response, FilterChain chain) {

        //將字符串中出現的":):"轉換成"^V^";
        request.requestStr = request.requestStr.replace(":):", "^V^")
                //后面添加的是便於我們觀察代碼執行步驟的字符串
                + "----FaceFilter()";
        chain.doFilter(request, response, chain);
        response.responseStr += "---FaceFilter()";
    }

}

第四步:定義責任鏈FilterChain

package com.bjsxt.dp.filter;

import java.util.ArrayList;
import java.util.List;

//過濾鏈條
public class FilterChain implements Filter{
    //用List集合來存儲過濾規則
    List<Filter> filters = new ArrayList<Filter>();
    //用於標記規則的引用順序
    int index=0;
    //往規則鏈條中添加規則
    public FilterChain addFilter(Filter f) {
        filters.add(f);
        //代碼的設計技巧:Chain鏈添加過濾規則結束后返回添加后的Chain,方便我們下面doFilter函數的操作
        return this;
    }
    public void doFilter(Request request,Response response,FilterChain chain){
        //index初始化為0,filters.size()為3,不會執行return操作
        if(index==filters.size()){
            return;
        }
        //每添加一個過濾規則,index自增1
        Filter f=filters.get(index);
        index++;
        //根據索引值獲取對應的規律規則對字符串進行處理
        f.doFilter(request, response, chain);
    }
}

第五步:測試一下我們的代碼

package com.bjsxt.dp.filter;

/*
 * 責任鏈模式:
 * 數據消息在進入數據庫之前,要被多種過濾規則進行處理,多種規則形成一種鏈,依次處理
 * 給定的數據消息
 */
public class Main {
    public static void main(String args[]) {
        //設定過濾規則,對msg字符串進行過濾處理
        String msg = ":):,<script>,敏感,被就業,網絡授課";
        //過濾請求
        Request request=new Request();
        //set方法,將待處理字符串傳遞進去
        request.setRequest(msg);
        //處理過程結束,給出的響應
        Response response=new Response();
        //設置響應信息
        response.setResponse("response:");
        //FilterChain,過濾規則形成的攔截鏈條
        FilterChain fc=new FilterChain();
        //規則鏈條添加過濾規則,采用的是鏈式調用
        fc.addFilter(new HTMLFilter())
        .addFilter(new SensitiveFilter())
        .addFilter(new FaceFilter());
        //按照FilterChain的規則順序,依次應用過濾規則
        fc.doFilter(request, response,fc);
        //打印請求信息
        System.out.println(request.getRequest());
        //打印響應信息
        System.out.println(response.getResponse());
        /*
         * 處理器對數據進行處理
         * --|----|---數據--|-----|--- 
         * 規則1      規則2                 規則3       規則4
         */
    }
}

運行結果:

^V^,[script],,就業,網絡授課----HTMLFilter() ---sensitiveFilter()----FaceFilter()
response:---FaceFilter()---sensitiveFilter()---HTMLFilter()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM