責任鏈模式及其使用場景

1.責任鏈模式定義

責任鏈模式(Iterator Pattern), 是行爲型設計模式之一。這種模型結構有點類似現實生活中鐵鏈,由一個個鐵環首尾相接構成一條鏈,如果這種結構用在編程領域,則每個節點可以看做一個對象,每個對象有不同的處理邏輯,將一個請求從鏈的首端發出,沿着鏈的路徑依次傳遞每個節點對象,直到有對象處理這個請求爲止,我們將這樣一種模式稱爲責任鏈模式。

2. 責任鏈模式使用場景

1.多個對象可以處理同一個請求,但具體由哪個對象處理則在運行時動態決定。
2. 在請求處理者不明確的情況下向對個對象中的一個提交一個請求。
3. 需要動態處理一組對象處理請求。

3. 責任鏈模式實現

3.1 簡單實現

下圖是簡單實現的責任鏈模式類UML圖
在這裏插入圖片描述
角色介紹
AbsHandler:抽象處理者角色,聲明一個請求處理的方法,並在其中保持一個對下一個處理節點Handler對象的引用。
ConcreteHandler:具體處理者角色,對請求進行處理,如果不能處理則將該請求轉發給下一個節點上的處理對象。

  1. 定義抽象Handler
public abstract class AbsHandler {
    protected AbsHandler successor;

    public abstract void handleRequest(String condition);
}
  1. 定義具體實現ConcreteHandler1ConcreteHandler2
public class ConcreteHandler1 extends AbsHandler {
    @Override
    public void handleRequest(String condition) {

        if(condition.equals("ConcreteHandler1")){
            return;
        }else{
            successor.handleRequest(condition);
        }
    }
}
public class ConcreteHandler2 extends AbsHandler {
    @Override
    public void handleRequest(String condition) {

        if(condition.equals("ConcreteHandler2")){
            return;
        }else{
            successor.handleRequest(condition);
        }
    }
}
  1. Client端調用
public class Client {
    public static void handlerRequest(){
        AbsHandler handler1 = new ConcreteHandler1();
        AbsHandler handler2 = new ConcreteHandler2();
        handler1.successor = handler2;
        handler2.successor = handler1;

        handler1.handleRequest("ConcreteHandler2");
    }
}

傳入的"ConcreteHandler2"最終有Handler2完成處理。

3.2 擴展實現

簡化版實現中我們的請求對象只是一個字符串,多數情況下,責任鏈中請求和對應處理規則是不盡相同的,在這種情況下可以將請求進行封裝,同時對請求的處理規則也進行封裝作爲一個獨立的對象。
下圖是擴展後的責任鏈模式的類UML圖
在這裏插入圖片描述
在AbstractHandler抽象處理者中,其聲明瞭處理者對象處理請求的方法和獲取處理級別的方法,並對具體處理轉發邏輯進行實現。

  1. 定義AbstractHandler
public abstract class AbstractHandler {

    protected static final String TAG = AbstractHandler.class.getSimpleName();

    protected AbstractHandler nextHandler;

    public final void handleRequest(AbstractRequest request){

        if(getHandleLevel() == request.getRequestLevel()){
            handle(request);
        }else{
            if(nextHandler!=null){
                nextHandler.handle(request);
            }else{
                //當所有處理者對象均不能處理該請求時輸出
                Log.d(TAG,"All of handler can not handle the request");
            }
        }
    }

    protected abstract int getHandleLevel();

    protected abstract void handle(AbstractRequest request);
}
  1. 定義AbstractRequest
public abstract class AbstractRequest {

    private Object object;

    public AbstractRequest(Object object){
        this.object = object;
    }

    public Object getContent(){
        return object;
    }

    public abstract int getRequestLevel();
}
  1. 定義Handler類具體實現
public class Handler1 extends AbstractHandler {

    @Override
    protected int getHandleLevel() {
        return 1;
    }

    @Override
    protected void handle(AbstractRequest request) {

        Log.d(TAG, "Handler1 handler request:"+request.getRequestLevel());
    }
}

public class Handler2 extends AbstractHandler {

    @Override
    protected int getHandleLevel() {
        return 2;
    }

    @Override
    protected void handle(AbstractRequest request) {
        Log.d(TAG, "Handler2 handler request:"+request.getRequestLevel());
    }
}

public class Handler3 extends AbstractHandler {

    @Override
    protected int getHandleLevel() {
        return 3;
    }

    @Override
    protected void handle(AbstractRequest request) {
        Log.d(TAG, "Handler3 handler request:"+request.getRequestLevel());
    }
}
  1. 定義Request類具體實現
public class Request1 extends AbstractRequest {

    @Override
    public int getRequestLevel() {
        return 1;
    }

    public Request1(Object object) {
        super(object);
    }

    @Override
    public Object getContent() {
        return super.getContent();
    }
}

public class Request2 extends AbstractRequest {

    @Override
    public int getRequestLevel() {
        return 2;
    }

    public Request2(Object object) {
        super(object);
    }

    @Override
    public Object getContent() {
        return super.getContent();
    }
}

public class Request3 extends AbstractRequest {

    @Override
    public int getRequestLevel() {
        return 3;
    }

    public Request3(Object object) {
        super(object);
    }

    @Override
    public Object getContent() {
        return super.getContent();
    }
}
  1. Client建立責任鏈處理請求
public class Client {

    public static void handleRequest(){
        AbstractHandler handler1 = new Handler1();
        AbstractHandler handler2 = new Handler2();
        AbstractHandler handler3 = new Handler3();

        handler1.nextHandler = handler2;
        handler2.nextHandler = handler3;

        //構造三個請求者對象
        AbstractRequest request1 = new Request1("Request1");
        AbstractRequest request2 = new Request2("Request2");
        AbstractRequest request3 = new Request3("Request3");

        //總是從鏈式的首端發起請求
        handler1.handleRequest(request1);
        handler1.handleRequest(request2);
        handler1.handleRequest(request3);
    }
}

4. 責任鏈模式實戰

在實際開發中,經常會出現在一個DbusReceiver或者BroadcastReceiver中處理所有的Signals或者Actions,通過if…else來區分不同的signal或者Action,這樣雖然簡單,但是將所有的業務處理方法一個類中處理,不免會造成業務結構不清晰、代碼冗長難懂。一種可行的方法就是通過責任鏈模式設計,將業務做拆分,將同一類型的業務放到一個單獨類中處理,這樣的處理能極大優化代碼結構,使得業務邏輯更加清晰。DbusReceiver及BroadcastReceiver只作爲消息的分發中心,每接收到一個信號或者action,將其交給責任鏈處理,各個責任鏈只負責處理自己關心的Signal或者Action。

對於Dbus的接收的責任鏈模式實現如下:

  1. 定義處理Signal的AbstractHandler
public abstract class AbsDbusHandler {

    protected final Context mContext;

    protected Handler mHandler = new Handler();
    protected AbsDbusHandler nextHandler;

    public AbsDbusHandler(Context context) {
        mContext = context;
    }

    public abstract boolean handle(String sigName, int argLength, List<DbusObj> argList);

    protected String getTag() {
        return getClass().getSimpleName();
    }

}
  1. 定義處理Signal的具體Handler
////處理Upgrade相關的Signal
public class UpgradeSignalsHandler extends AbsDbusHandler {
    public UpgradeSignalsHandler(Context context) {
        super(context);
    }

    @Override
    public boolean handle(String sigName, int argLength, List<DbusObj> argList) {
        if (sigName.equals(DbusSignal.SIGNAL_UPGEADE)) {
            //do some thing
           
            } else {
              // other thing
            }
            return true;
        } else {
            if (nextHandler != null) {
                return nextHandler.handle(sigName, argLength, argList);
            } else {
                return false;
            }
        }
    }
}

//處理MetaSwitch相關的Signal
public class MetaSwitchSignalsHandler extends AbsDbusHandler {

    private static Thread checkDevState;


    public MetaSwitchSignalsHandler(Context context) {
        super(context);
    }

    @Override
    public boolean handle(String sigName, int argLength, List<DbusObj> argList) {

        if (sigName.equals(DbusSignal.SIGNAL_METASWITCH_REQ_LOGIN)||
        sigName.equals(DbusSignal.SIGNAL_METASWITCH_LOGIN_ERROR)) {
            //do some thing
            return true;
        } else {
            if (nextHandler != null) {
                return nextHandler.handle(sigName, argLength, argList);
            } else {
                return false;
            }
        }
    }
}
  1. 通過一個簡單工廠方法創建一個責任鏈
public class HandlerChainFactory {
    private static AbsDbusHandler dbusHandler;

    public static AbsDbusHandler productDbusChain(Context context) {

        if(dbusHandler == null){
            AbsDbusHandler metaSwitchSignalsHandler = new MetaSwitchSignalsHandler(context);
            AbsDbusHandler audioSignalsHandler = new AudioSignalsHandler(context);
            AbsDbusHandler upgradeSignalsHandler = new UpgradeSignalsHandler(context);
            metaSwitchSignalsHandler.nextHandler = audioSignalsHandler;
            audioSignalsHandler.nextHandler = upgradeSignalsHandler;
            dbusHandler = metaSwitchSignalsHandler;
        }

        return dbusHandler;
    }
  1. Client調用責任鏈處理Signal
private DbusCallback dbusCallback = new DbusCallback() {
        @Override
        public void onCallback(int sigId, String sigName, int argNum, List<DbusObj> argList) {
            if (!getDbusHandler().handle(sigName, argNum, argList)) {
                //責任沒有處理的信號在這裏處理
            }

        }
    };

對於Action的接收的責任鏈模式實現:
基本思路和Dbus Signal處理類似,Receiver只是作爲一個消息分發中心,每次接收到一個Intent,將其傳入到責任鏈中進行處理。

5. 總結

責任鏈中一個處理者對象,其中只有兩個行爲,一是處理請求,二是將請求轉送給下一個節點,不允許某個處理者對象在處理了請求後又將請求轉送給上一個節點的情況。對於一條責任鏈來說,一個請求最終只有兩種情況,一是被某個處理對象所處理,另一個是所有對象均未對其處理,前一種情況稱該責任鏈爲純的責任鏈,對於後一種情況稱爲不純的責任鏈,實際應用中,多爲不純的責任鏈。

責任鏈在Android源碼中比較類似的實現莫過於View的事件分發處理,對於觸摸事件,Android總是從VIewTree最頂端,從上而下處理,具體處理流程主要通過dispatchTouchEventonTouchEvent 等函數處理,具體可以查看相關源碼。ViewGroup事件投遞的遞歸調用類似一條責任鏈,一旦其尋找到責任者,那麼將有責任者持有並消費掉該次事件,具體體現在View的onTouchEvent方法中返回值的設置,如果onTouchEvent返回False,那麼意味着當前View不會是該次事件的責任人,將不會對其持有:如果爲true則相反,此時View會持有該事件並不再向外傳遞。

另外,著名的OKHttp3框架及Netty NIO框架也都使用了責任鏈模式設計。OkHttp3中Interceptor以及Netty中ChannelInboundHandlerAdapter都是責任鏈模式設計的典型。那麼可以總結爲責任鏈模式是處理數據流比較好的模式設計。
附一張OkHttp實現原理圖
在這裏插入圖片描述

如果你願意,所有的if…else語句及switc…case語句你都可以使用責任鏈模式進行改造,但是大部分情況下,這樣做都是不必要的。而只有當過多的if…else分支導致代碼難以維護時,考慮使用責任鏈模式進行業務拆分。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章