Functional Option Pattern
Fuctional Option PatternはGo言語において構造体の初期化時にオプション引数を与えるためのデザインパターンで、元ネタはRob Pike氏のSelf-referential functions and the design of options 、Dave Cheney氏のFunctional options for frendly APIS です。 Go言語には他の言語でオプション引数やキーワード引数と呼ばれる、省略可能な引数が存在しません。 通常は大きな問題は無いのですが、しかし、構造体の初期化時には、省略可能引数がほしくなる場合もあります。 Dave Cheney氏の記事にもある例を見てみましょう。 例 1 2 3 4 5 6 7 8 9 10 11 12 13 type Server struct { listener net.Listener } func NewServer(addr string) (*Server, error) { l, err := net.Listen("tcp", addr) if err != nil { return nil, err } srv := Server{listener: l} go srv.run return &srv, nil } よくある構造体の初期化関数です。 初期化が上手くいけば、ポインタとnilを、上手くいかなければnilとエラーを返す形になっています。 ここで、Serverになにがしかの拡張を加えることを考えます。たとえばタイムアウトや、TLS対応等です。 しかしこれらは指定する必要が無い場合もあります。 Go言語を用いたアプローチですぐに思いつくのは、オプションの組み合わせの数だけ初期化関数を作成することですね。(たとえば、With...というサフィックスを使って) しかしこれは、オプションの数が増えると、作成しなければならない関数の数が膨大になっていきます。 保守の観点から見てもこれは余りうれしくありません。 Config構造体を用いる そこでよく用いられるのが、設定を保持する構造体を用いる方法です。 例としては、以下の様にします。 1 2 3 4 5 6 7 8 type Config struct { Timeout time.Duration Cert *tls.Cert } func NewServer(addr string, config Config) { // ... } これも良く用いられているパターンです。 しかし、オプションを一切与えない場合のパターンを考えてみましょう。 ...