HTTP 라우터로 고차 함수 시연

얼마 전에 나는 깊은 숲 속에서 소프트웨어를 재작업하는 친구와 이야기를 나누고 있었습니다. 키가 HTTP 경로이고 값이 함수인 전역map이 관련되었습니다. 플러그인은 기능 참조를 할당하여 지도에 경로를 추가합니다. 그런 다음 핵심 설정 기능은 지도의 모든 경로를 실제 HTTP 라우터에 등록합니다. map의 목적이 명확하지 않았고 친구가 일부 플러그인이 서로 충돌한다고 말했습니다(예: Google 로그인과 Microsoft 로그인). 핵심 설정 기능은 실제로 사용할 충돌 플러그인을 결정합니다.

글로벌map에 대한 대안이 있을 수 있습니다. 플러그인이 경로를 라우터에 직접 추가하도록 하십시오! 그러나 임의의 조건을 구별하는 설정 기능은 어떻습니까? 플러그인이 스스로 결정하게 하십시오! 함수 유형 인수를 취하거나 함수 유형을 반환하는 함수로 정의되는 고차 함수를 입력합니다.

직접적인 라우터 종속성 없이 경로 등록



경로를 추가하려면 라우터struct를 제공하는 멋진 라이브러리가 있다고 가정합니다.

func (a *NiftyRouter) Register(method, path string, handler func())


반면에 경로를 추가하려는 많은 플러그인 기능이 있습니다. 플러그인과 구체적인 라우터struct의 강력한 결합을 피하기 위해 경로 등록 의도를 표현하는 함수 유형을 정의해 보겠습니다.

type RegisterRouteFunc func(method, path string, handler func())


구체적인 라우터struct를 사용하는 구현은 함수 일치RegisterRouteFunc 서명을 반환하는 고차 함수입니다.

func RegisterRouteNifty(router *NiftyRouter) RegisterRouteFunc {
    return func(method, path string, handler func()) {
        router.Register(method, path, handler)
    }
}


반환된 함수에서 router 인수가 어떻게 사용되어 closure 을 생성하는지 확인하십시오. RegisterRouteNifty가 프로그램 런타임 초기에 한 번만 호출되기 때문에 클로저 생성의 성능 저하를 무시할 수 있습니다(자세한 내용은 나중에 설명).

플러그인 인터페이스 정의



같은 맥락에서 플러그인을 추가할 목적으로 함수 유형을 생성합니다. 이 함수는 플러그인이 HTTP 경로를 등록할 수 있다는 사실을 전달하는 RegisterRouteFunc 인수를 받습니다.

type AddPluginFunc func(register RegisterRouteFunc)


각 플러그인은 AddPluginFunc 구현을 제공합니다.

func AddProfilePagePlugin() AddPluginFunc {
    return func(register RegisterRouteFunc) {
        register("GET", "/profile", func() {
            // ...
        })
    }
}


임의의 조건이 필요한 경우 명명된 함수에 필요한 입력을 인수로 추가합니다. 이것은 또 다른 폐쇄를 생성하지만 다시 그 영향은 미미합니다.

func AddGoogleLoginPlugin(config *Configuration) AddPluginFunc {
    return func(register RegisterRouteFunc) {
        if (config.Foo) {
            register(/* ... */)
        }
    }
}


여러 AddPluginFunc 를 하나의 함수로 구성하는 AddPluginFunc 함수도 있을 수 있습니다.

func AddPlugins(plugins ...AddPluginFunc) AddPluginFunc {
    return func(register RegisterRouterFunc) {
        for _, f := range plugins {
            f(register)
        }
    }
}


합치기



구성 요소가 제자리에 있으면 기본 기능을 조립할 수 있습니다.

func main() {
    // Some requirements
    var config *Configuration
    var router *NiftyRouter

    register := RegisterRouteNifty(router)

    AddPlugins(
        AddGoogleLoginPlugin(config),
        AddMicrosoftLoginPlugin(config),
        AddProfilePagePlugin(),
        // ...
    )(register)

    // Start the router...
}


물론 고차 함수는 다양한 상황에서 사용할 수 있습니다. 성능 저하를 피하기 위해 클로저를 생성할 때 약간의 주의가 필요합니다.

(코드 예제는 모두 이 게시물을 위해 작성되었습니다.)

좋은 웹페이지 즐겨찾기