Offer to come, dig friends take it! I am participating in the 2022 Spring Recruit Punch card activity. Click here for details.

Meaning of responsibility chain model

When reading OkHttp source code, I found that it is very clever in the process of handling interceptors. Combining the chain of responsibility mode, it transmits Request in the form of link, and then transmits Response in the direction of link.

The Chain of Responsibility pattern avoids coupling between the sender and receiver of the request by giving multiple objects the opportunity to process the request. Connect the objects into a chain and pass the request along the chain until an object processes it.

Next we write a chain of responsibility pattern modeled after OkHttp to handle requests and responses.

The instance

Requirement: A Request needs to go through four processes: Log, Header, Connect, and Call. Each process processes the Request separately and finally obtains the Response from the end of the process.

The specific process is shown in the figure above. Therefore, Chain, as a Chain, drives the beginning of the Request and is also the object that finally gets the Response.

  • The solid line is the complete process of a responsibility chain.ChainInitiate, go throughLogger->Header->Connect->CallAnd wait forCallThe result is processed, and then the direction of the result is passed up, throughCall->Connect->Header->Logger->Chain.
  • The dashed line is returned halfway through being consumed by an object, such as inHeaderThe step is abnormal and an empty is generatedResponseReturn, and the request flow becomesChain->Logger->Header, the return flow isHeader->Logger->Chain; This is the charm of the chain of responsibility model. Any object in the chain can be consumed and returned in advance without affecting the normal execution of the link.

Let’s show it in code.

coding

Class Chain(private val interceptorList: List<Interceptor>, private val index: Int, val request: request) {/** * call the chain object processing method */ fun process(request: request): Response {// also use index as subscript, Val next = Chain(interceptorList, index = this.index + 1); request) val interceptor = interceptorList[index] return interceptor.intercept(next) } } /** * [Request] */ class Request(var msg: String) { fun buildRequest(msg: String) = Request(msg) } /** * [Response] */ class Response(val msg: String) { fun buildResponse(msg: String) = Response(msg) }Copy the code

Chain, Request, and Response are defined

/** * [Interceptor] */ interface Interceptor {chain: chain): Response } class LoggerInterceptor : Interceptor { override fun intercept(chain: Chain): Response { val request = chain.request println("logger request: ${request.msg}") val response = chain.process(request.buildRequest("logger")) println("logger response: ${response.msg}") return response.buildResponse("logger") } } class HeaderInterceptor : Interceptor { override fun intercept(chain: Chain): Response { val request = chain.request println("header request: ${request.msg}") val response = chain.process(request.buildRequest("header")) println("header response: ${response.msg}") return response.buildResponse("header") } } class ConnectInterceptor : Interceptor { override fun intercept(chain: Chain): Response { val request = chain.request println("connect request: ${request.msg}") val response = chain.process(request.buildRequest("connect")) println("connect response: ${response.msg}") return response.buildResponse("connect") } } class CallInterceptor : Interceptor { override fun intercept(chain: Chain): Response { val request = chain.request println("call request: ${request.msg}") println() val response = Response("call") println("call response: ${response.msg}") return response } }Copy the code

Define the Interceptor base class and four chain objects;

fun main() {
    val interceptorList = mutableListOf<Interceptor>()
    interceptorList += LoggerInterceptor()
    interceptorList += HeaderInterceptor()
    interceptorList += ConnectInterceptor()
    interceptorList += CallInterceptor()
    val request = Request("init")
    val chain = Chain(interceptorList, 0, request)
    chain.process(request)
}
Copy the code

Pass four Chain objects into the Chain and make a request. Look at Log:

logger request: init
header request: logger
connect request: header
call request: connect

call response: call
connect response: call
header response: connect
logger response: header
Copy the code

Through Log, we can clearly see the execution process of the objects in each chain, enter the execution process of the objects in sequence, and finally reverse transfer the Response.