Android設計模式-責任鏈

簡述

責任鏈模式是一種對象的行爲模式。經過創建一條鏈來組織請求的處理者,請求將沿着鏈進行傳遞,請求發送者無須知道請求在什麼時候、何處以及如何被處理,實現了請求發送者與處理者的解耦。html

如Android 中的事件傳遞,Activity->ViewGroup->View,固然也能夠View->ViewGroup-> Activity ,android 中是U形事件傳遞android

另外OKhttp的interceptors實現,OkHttp發送網絡請求的一切核心功能,包括創建鏈接、發送請求、讀取緩存等,都是經過interceptors來實現的。這些interceptors在運行的時候彼此協做,構成了一個責任鏈interceptor chaingit

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
        interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
            originalRequest, this, eventListener, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
}
複製代碼

在 OkHttp 中,命令對象就是 Request 對象,處理對象就是每個 Interceptor 對象。每一個 interceptor 對 request 進行一些步驟的處理,而將其他的工做交給下一個 interceptor。注意到,責任鏈中的處理對象若是能夠全權處理命令對象,則不須要交給下一個處理對象。OkHttp 中的 CacheInterceptor 也是具備全權處理的能力。若是請求的結果已經緩存,則不須要再交給 ConnectInterceptor 等進行鏈接服務器、發送請求的處理,直接返回已緩存的 response 便可。github

例如常見的流程審批(固然在企業級APP中由服務端處理)編程

fun main(args: Array<String>) {
    // 引用鏈
    val cto = CTO(null)
    val department = DepartmentLeader(cto)
    val group = GroupLeader(department)

    //
    group.handleEvent(FlowEvent("filepath ", 113))
}


data class FlowEvent(val filePath: String, val fileID: Int)

interface FlowHandler {
    val next: FlowHandler?
    fun handleEvent(event: FlowEvent)
}


class GroupLeader(override val next: FlowHandler?) : FlowHandler {

    override fun handleEvent(event: FlowEvent) {
        when (event.fileID) {
            // 根據文件ID分配審批權限 處理
            111 -> print("GroupLeader收到流程:${event.filePath}")
            // 不然轉發
            else -> when (next) {
                // 轉發到下一級
                is FlowHandler -> {
                    println("GroupLeader: 此流程被轉發了")
                    next.handleEvent(event)
                }
                else -> println("GroupLeader: 此流程不能被處理")
            }
        }
    }
}


class DepartmentLeader(override val next: FlowHandler?) : FlowHandler {
    override fun handleEvent(event: FlowEvent) {
        when (event.fileID) {
            // 根據文件ID分配審批權限 處理
            112 -> println("DepartmentLeader收到流程:${event.filePath}")
            // 不然轉發
            else -> when (next) {
                // 轉發到下一級
                is FlowHandler ->  {
                    println("DepartmentLeader: 此流程被轉發了")
                    next.handleEvent(event)
                }
                else -> println("DepartmentLeader: 此流程不能被處理")
            }
        }
    }
}

class CTO(override val next: FlowHandler?) : FlowHandler {
    override fun handleEvent(event: FlowEvent) {
        when (event.fileID) {
            // 根據文件ID分配審批權限
            113 -> println("CTO收到流程 :${event.filePath},正在處理")
            else -> println("CTO: 此流程不能被處理")

        }
    }
}
複製代碼

輸出:api

GroupLeader:  此流程被轉發了
DepartmentLeader:  此流程被轉發了
CTO收到流程文件:filepath 
複製代碼

以上能夠參見責任鏈的工做機理,整個鏈條的每一個處理環節都有 對其輸入參數的校驗,只有輸入參數在責任鏈環節的有效接收範圍以內,才能處理相關的邏輯緩存

偏函數

偏函數是數學中的概念,指的是定義域X中可能存在某些值在值域Y中沒有相對應的值。bash

一個多元函數傳入了部分參數以後的獲得的新的函數。 參數的固定通常使用默認參數+具名參數。若是須要固定的參數在中間,雖說能夠經過具名參數來解決,可是很尷尬,由於必須使用一大堆具名參數。g服務器

Function參見這裏markdown

fun main(args: Array<String>) {
   val chain =  GroupLeader orElse  DepartmentLeader orElse CTO
    chain(FlowEvent("xxxxx",113))
}

/**
 * 責任鏈模式中各環節對於輸入的校驗已經處理邏輯的問題。
 *
 * 協變-  泛型對象做爲函數的參數,逆變- 泛型做爲內部方法的返回。
 *
 * @param check 校驗函數
 * @param handle 處理函數
 */
class ChainFunction<in P1, out R>(
        private val check: (P1) -> Boolean,
        private val handle: (P1) -> R) : (P1) -> R {
    // 進行有效性檢驗 傳遞參數p1
    override fun invoke(p1: P1): R {
        if (check(p1)) {
            // 校驗經過執行handle函數
            return handle(p1)
        } else {
            // 檢驗不經過拋出異常
 			  throw  IllegalArgumentException("事件: ($p1) 沒法被處理 ")
        }
    }

    fun isChecked(p1: P1) = check(p1)
}

// 利用中綴函數造成引用鏈
infix fun <P1, R> ChainFunction<P1, R>.orElse(function: ChainFunction<P1, R>): ChainFunction<P1, R> {
    return ChainFunction({
        this.isChecked(it) || function.isChecked(it)
    }) {
        when {
            this.isChecked(it) -> this(it)
            else -> function(it)
        }
    }
}


val GroupLeader = {
    val event: (FlowEvent) -> Boolean = {
        it.fileID == 111
    }

    val handler: (FlowEvent) -> Unit = {
        print("GroupLeader已處理該流程:filePath ${it.filePath}")
    }
    // 傳遞
    ChainFunction(event,handler)
}()

val DepartmentLeader = {
    val event: (FlowEvent) -> Boolean = {
        it.fileID == 112
    }

    val handler: (FlowEvent) -> Unit = {
        print("DepartmentLeader已處理該流程:filePath ${it.filePath}")
    }
    // 傳遞
    ChainFunction(event,handler)
}()

val CTO = {
    val event: (FlowEvent) -> Boolean = {
        it.fileID == 113
    }

    val handler: (FlowEvent) -> Unit = {
        print("CTO已處理該流程:filePath ${it.filePath}")
    }
    // 傳遞
    ChainFunction(event,handler)
}()

複製代碼
CTO已處理該流程:filePath  xxxxx
複製代碼

若是責任鏈過長,或者鏈上的事件傳遞須要判斷處理時間太長的話會影響性能,尤爲是遞歸循環。


參考:

funKTionale 《Kotlin核心編程》

相關文章
相關標籤/搜索