[Design Pattern] Encapsulate a network request lib - 1. DIP: Dependence Inversion Principle

Zhentiw發表於2024-12-01

Three layers design

[Design Pattern] Encapsulate a network request lib - 1. DIP: Dependence Inversion Principle

  • Low level implementation Layer: using low level implementation to complete basic operation.
    • For the network request, we can use the lib such as axios, which internally using xhr, or we can also use fetchdirectly from node.js
  • request-core: Provide high-level network control features, including request serialization, request parallelism, and request deduplication.
  • request-bus: Bind to the busniess logic

Current design is

  • request-bus depends on request-core
  • request-core depends on low level implementation layer
  • low level implementation layer might use different built-in method or 3-rd party library

Impove the design

For low level implementation layer, as we can see it, the solution can be different

  • xhr
  • fetch
  • axios

Which mean that this layer is not stable. Not stable means that once we might swap the current built-in methods or 3-rd party library for a better one in future. For example, if current you are using xhrin the old project, you might want to upgrade it by using fetchor axios; or you found axiosis not good enough, you want to update to other libraray again in the further future again.

The problem is the low level implementation layer is a base layer. If this layer is not stable, any change happens in this layer might affect upper layer, such as request-corelayer. Which might further affect request-buslayer.

Therefore, we need to find a solution can isolate this unstablness.

For that we can use a design pattern called DIP (Dpendence Inversion Principle), our aims is to decouple request-coreand low level implementation layer.

Dependence Inversion Principle

  • High level implementation should not rely on low level implementation details
  • Both should rely on interface

Improved desgin

[Design Pattern] Encapsulate a network request lib - 1. DIP: Dependence Inversion Principle

Now request-coreonly provide interface, doesn't provide implementation.

// exmaple
export interface Requestor {
    get(url: string, options: RequestOptions): Promise<Response>
    //
}

let req: Requestor
export function inject(request: Requestor) {
  req = requestor;
}

export function createParalleRequestor(maxCount = 4) {
    const req = useRequestor()
    // ...futher setting
    return req
}

export function createSequenceRequestor() {
    const req = useRequestor()
    // ...futher setting
    return req
}

request-axios-implexample code

import { Requestor } from 'request-core'
import axios from 'axios'

const ins = axios.create();

export requestor: Requestor {
    get(url, options) {
        // use axios
    },
    // other methods
}

request-busexample code

import {inject} from 'request-core'
import {requestor} from 'request-axios-impl'
inject(requestor)

In future, if there is any changes in low level implementation layer, we don't need to change request-core, we only need to add a new implementation, for example request-fetch-impl.ts

import {Requestor} form 'request-core'

export requestor: Requestor = {
    get(url, options?) {
        // using fetch
    },
    post(url, data, options?) {
    },
    // other methods
}

Only change in request-bus layer

- import {requestor} from 'request-axios-impl';
+ import {requestor} from 'request-fetch-impl';
inject(requestor)

相關文章