본문 바로가기
golang/design pattern

golang design pattern #5 Adapter

by PudgeKim 2021. 11. 12.

Adapter 패턴은 어댑터라는 말 그대로 서로 다른 구조체간의 연결을 하기 위한 패턴으로
interface를 활용하여 연결하게 됩니다.

golang의 http 관련 내부 패키지중에 HandlerFunc라는 타입이 있는데
HandlerFunc가 어댑터 패턴으로 구현되어 있습니다.

 

1
2
3
4
5
type HandlerFunc func(ResponseWriter, *Request)
 
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}
cs

go에 기본적으로 구현되어 있는 HandlerFunc의 코드입니다.

보다시피 HandlerFunc 타입은 ServeHTTP 메서드를 구현하고 있습니다.

 

1
2
3
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}
cs

역시 go에 기본적으로 구현되어있는 Handler 타입입니다. 

Handler 타입을 구현하려면 ServeHTTP를 구현해야 합니다. 즉, HandlerFunc는 Handler 타입을 구현하게 도와주는 어댑터입니다.

 

HandlerFunc가 어떻게 쓰이는지 좀 더 정확히 알아보겠습니다.

 

1
2
3
func Home(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Here is my home"))
}
cs

위에 함수를 http.Handle함수의 인자로 넣고 싶다고 가정해보겠습니다.

 

1
func Handle(pattern string, handler Handler)
cs

그런데 공식문서에 Handle 함수의 정의는 위와 같습니다.

 

1
http.Handle("/home", Home)
cs

즉, 우리는 위와 같은 코드를 작성하고 싶지만
Home 함수는 Handler 타입이 아니기 때문에 위 같은 코드를 작성할 수 없습니다.

이 때 위에서 살펴본 어댑터 함수인 HandlerFunc가 쓰이게 됩니다.

 

1
http.Handle("/home", HandlerFunc(Home))
cs

이렇게 HandlerFunc로 감싸주면 에러없이 동작합니다.

 

다시 HandlerFunc 함수를 살펴보겠습니다.

1
2
3
4
5
6
type HandlerFunc func(ResponseWriter, *Request)
 
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}
 
cs

f(w, r) 코드는 결국 func(ResponseWriter, *Request)에 해당하는 함수를 그대로 실행하는 것뿐입니다.

 

이해를 돕기 위해 간단한 예제를 보여드리겠습니다.

1
2
3
4
5
6
7
8
9
10
11
type testFunc func(string) string
 
func Hello(name string) string {
    return fmt.Sprintf("%s hello", name)
}
 
func main() {
    t := testFunc(Hello)
    fmt.Println(t("kim"))
}
cs

이렇게 t("kim")은 결국 Hello("kim")과 같은 동작을 합니다.

그러나 HandlerFunc의 경우 ServeHTTP가 구현되어있으므로 HandlerFunc로 감싼 타입은
Handler 타입이 적용되기 때문에 어댑터의 역할을 하게 됩니다.

 

http.Handler는 middleware를 만들 때 많이 사용하게 됩니다.

예를 들어 json header를 붙여주는 middleware를 만들어보겠습니다.

1
2
3
4
5
6
func AddJsonHeaderMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Add("Content-Type""application/json")
        next.ServeHTTP(w, r)
    })
}
cs

함수의 인자로 http.Handler를 받은 후 json header를 붙여주고
인자로 받은 함수를 실행시켜주는 middleware 입니다.

'golang > design pattern' 카테고리의 다른 글

golang design pattern #7 Composite  (0) 2021.11.12
golang design pattern #6 Bridge  (0) 2021.11.12
golang design pattern #4 Singleton  (0) 2021.11.11
golang design pattern #3 Prototype  (0) 2021.11.11
golang design pattern #2 Factory  (0) 2021.11.10