Go言語でポリモーフィズムを実装 ～http.HandlerFuncに学ぶ～ #golang

# はじめに
* Go言語でポリモーフィズムを実装しようとするとインターフェイスを使って実装するかと思います。
* ここではもう一つ関数型を使ってのポリモーフィズムを紹介してみる。
* 正直に言いますが下記の記事を大変に参考にさせていただきました。めちゃめちゃ勉強になりました！ありがとうございます！  
[インタフェースの実装パターン #golang](https://qiita.com/tenntenn/items/eac962a49c56b2b15ee8)


# ポリモーフィズム(インターフェイスを使う)
インターフェイスを用意して構造体に実装します。
インターフェイスのメソッドを実装していれば、どんな構造体も実装できます。
言葉だけではぜんぜん理解できないので、下記にサンプルコードを用意しました。

やりたいことは、 `call()` というメソッドに多様性を持たせてみます。

* `MainCaller` 構造体に、 `MainInterface` を実装し `call()` というメソッドを実行できるようにします。
* `call()` メソッドを持つ、 `Normal` 構造体と `Change` 構造体を用意しそれぞれ振る舞いの違う `call()` を実行してみます。

```golang
package main

import "fmt"

// call メソッドを持つインターフェイスを定義します
type MainInterface interface {
        call(string, string) string
}

//------------------------------------
// インターフェイスを実装します
type MainCaller struct {
        MainInterface
}

//------------------------------------
type Normal struct {
}

func (n *Normal)call(x, y string) (str string){
        str = fmt.Sprintf("%v , %v", x, y)
        return
}

//------------------------------------
type Change struct {
}

func (c *Change)call(x, y string) (str string){
        str = fmt.Sprintf("change %v , %v", y, x)
        return
}

//------------------------------------

func main() {
        var m MainCaller

        fmt.Println("----- Sample 1 -----")
        var n = Normal{}

        m.MainInterface = &n
        fmt.Println(m.call("Hello", "World"))

        fmt.Println()

        fmt.Println("----- Sample 2 -----")
        var c = Change{}

        m.MainInterface = &c
        fmt.Println(m.call("Hello", "World"))
}
```
実行結果

```
----- Sample 1 -----
Hello , World

----- Sample 2 -----
change World , Hello

```

`Normal` も `Change` も `call` メソッドを持ち、インターフェイスに定義してあるメソッド形式と同じため、 `MainCaller` の `MainInterface` にポインタを渡すことができます。
実行結果をみるとわかるように、 同じメソッド `m.call("Hello", "World")` を実行しているのに結果が変わることがわかりました。

# ポリモーフィズム(type Funcを使う)
ポリモーフィズムを実現するためにもう一つの方法があります。

## http.HandleFunc に学ぶ
その前に `http.HadlerFunc` を見てみましょう。

https://golang.org/src/net/http/server.go?#L1959

```
type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}
.........
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}
```
やや見慣れない書き方をしてます。
`Handler` インターフェイスは `ServeHTTP(ResponseWriter, *Request)` 関数が定義されています。
`HandlerFunc` は`func(ResponseWriter, *Request)` という関数型として定義されています。
そしてその`HandlerFunc` という関数を実装しています。
そうなると`HandlerFunc` は`Handler` インターフェイスの関数を満たしているので、`Handler` としての振る舞いを実装していることになります。

どういうことかというと、ざっくり言えば、`HandlerFunc` の関数型を満たす関数を定義しておけば、他からは`ServeHTTP(ResponseWriter, *Request)` として実行できる。
ってことです。

言葉だけではよくわからない(俺もよくわからない)と思いますのでサンプルコードを見てみましょう。

```golang
package main

import "fmt"

// インターフェイス
// call(string, string) string が定義されていることに注意
type MainInterface interface {
        call(string, string) string
}

type MainCaller struct {
        MainInterface
}

// 関数型の定義
type SampleFunc func(string, string) string

func (s SampleFunc) call(x, y string) string {
        return s(x, y)
}

// SampleFunc を満たす関数その１
func normalFunc(x, y string) (str string){
        str = fmt.Sprintf("%v , %v", x, y)
        return
}

// SampleFunc を満たす関数その２ 
func changeFunc(x, y string) (str string){
        str = fmt.Sprintf("change %v , %v", y, x)
        return
}

func main() {
        var m MainCaller

        fmt.Println("----- Sample 1 -----")
        // normalFunc をSampleFunc型にキャスト
        var sf1 = SampleFunc(normalFunc)

        m.MainInterface = sf1
        fmt.Println(m.call("Hello", "World"))

        fmt.Println("----- Sample 2 -----")
        //  changeFunc  をSampleFunc型にキャスト
        var sf2 = SampleFunc(changeFunc)

        m.MainInterface = sf2
        fmt.Println(m.call("Hello", "World"))
}

```
`normalFunc` も `changeFuc` も関数として定義したにもかかわらず、`func(string, string) string` 型を満たしているので`SampleFunc` 型にキャストでき、どちらも`call(string, string) string` 関数として実行できています。
こんな感じのポリモーフィズムの実現方法もあります。  

# おまけ
## どっちがいいのか？
どっちの方法がいいのかと言われると、ケースバイケースになるのでどちらがいいなどはありません。 

上記の例で挙げた`Handler` インターフェイスですが、ドキュメントをよく見ると`timeoutHandler` や `redirectHandler` として実装したり、もしくは自分で`HandlerFunc` を自分で定義して登録して`ServeHTTP` を実行することもできます。

ここで「[Goプログラミング実践入門　標準ライブラリでゼロからwebアプリを作る](https://amzn.to/2SJmRU7)」から引用してみましょう。
この本はGo言語でWebプログラミングをするうえでとても参考になりました。 

> P73
　ハンドラ関数を使うほうがすっきりして、同じように仕事ができるのなら、ハンドラを使うのはいったいどうしてなのでしょうか。これは結局は設計の問題になります。既存のインタフェースがあるなら、あるいはハンドラとしても使える型がほしいなら、単にそのインタフェースにメソッドServeHTTPを追加すれば、URLに割り当てられるハンドラを得ることができます。またそれによって、構築するWebアプリケーションのモジュール性を高められます。 

設計上の方向性の問題のようです。 

## ちなみに
ちなみにですが、先日Qiitaに書きましたがGo言語でロガーgologger を作ってみました。
[Go言語でロガー gologgerを作ってみた](https://qiita.com/suganoooo/items/9b48fdc49e45ed517f28)
その時にJSON形式のフォーマットをするときに関数型で定義してポリモーフィズムを実現しています。
https://github.com/suganoo/gologger/blob/master/gologger.go#L133

```golang
// フォーマットを変更する関数
func (g *Gologger)SetOutputFormat(typeId OutputFmtType) {
	switch typeId {
	case FmtDefault:
		g.FormatterInterface = MarshallFunc(defaultFormat)
	case FmtJSON:
		g.FormatterInterface = MarshallFunc(jsonFormat)
	default:
		g.FormatterInterface = MarshallFunc(defaultFormat)
	}
}

// Log Format
type FormatterInterface interface {
	marshall(*Gologger, string, string) string
}

type MarshallFunc func(*Gologger, string, string) string
func (m MarshallFunc) marshall(g *Gologger, logLevel string, msg string) (logMsg string){
	return m(g, logLevel, msg)
}

// デフォルトのフォーマット関数
func defaultFormat(g *Gologger, logLevel string, msg string) (logMsg string){
.....
}

// JSON形式のフォーマット関数
func jsonFormat(g *Gologger, logLevel string, msg string) (logMsg string){
....
}
```

インターフェイスを実装するように構造体を定義しようと考えましたが、少し行数が多くなること、その構造体自体に他にやらせることがないこと、から関数型で定義してしまえばいいと考えてこのようにしました。

参考にしてみてください。