雑めも
-
ストラテジーパターン
- アルゴリズム(ストラテジー)を注入して使う。Excelストラテジー、PDFストラテジー、Nilストラテジーのどれか。
- それぞれのストラテジーごとに、構造体が違うため保持できるデータも異なる(
Excel.excel
とPdf.pdf
の箇所)
-
Null Object
- Nilストラテジーは Null Objectパターンで、
nil
ではなくて処理をしない構造体を渡しておくと実行時に nil チェックが必要なくなる
- Nilストラテジーは Null Objectパターンで、
-
インジェクション
- ストラテジーを注入するタイミングがコンストラクタによる生成時かメソッドを実行時によってやり方が異なる
ストラテジーパターン(コンストラクタインジェクション)
package main
import "fmt"
func main() {
var ct Content
// Excel
ct = Content{Name: "file1.xlsx", Data: Excel{}}
ct.Load()
ct.Print()
// Pdf
ct = Content{Name: "file2.pdf", Data: Pdf{}}
ct.Load()
ct.Print()
// Null
ct = Content{Name: "unknown", Data: Nil{}}
ct.Load()
ct.Print()
}
// Content
//
// ファイルに対するラッパー.
type Content struct {
Name string
Data ExcelOrPdf
}
func (c Content) Load() { c.Data.Load() }
func (c Content) Print() { fmt.Println(c.Name, c.Data.Text()) }
// ストトラテジーのInterface
type ExcelOrPdf interface {
Load()
Text() string
}
// Excel
//
// Excel ストラテジー
type Excel struct {
excel int64 // excel のライブラリのデータを入れる
}
func (e Excel) Load() { fmt.Println("Excel load") }
func (e Excel) Text() string { return "Excel print done" + string(e.excel) }
// PDF
//
// PDF ストラテジー
type Pdf struct {
pdf string // pdf のライブラリのデータを入れる
}
func (p Pdf) Load() { fmt.Println("PDF load") }
func (p Pdf) Text() string { return "PDF print done" + p.pdf }
// Nil
//
// NullObject ストラテジー
type Nil struct{}
func (n Nil) Load() { fmt.Println("<Nil load>") } // noop
func (p Nil) Text() string { return "<Nil print done>" } // noop
ストラテジーパターン(メソッドインジェクション)
package main
import "fmt"
func main() {
var ct Content
// Excel
ct = Content{Name: "file1.xlsx"}
excel := Excel{}
ct.Load(excel)
ct.Print(excel)
// Pdf
ct = Content{Name: "file2.pdf"}
pdf := Pdf{}
ct.Load(pdf)
ct.Print(pdf)
// Null
ct = Content{Name: "unknown"}
it := Nil{}
ct.Load(it)
ct.Print(it)
}
type Content struct {
Name string
}
// Load
type Loader interface{ Load() }
func (c Content) Load(loader Loader) { loader.Load() }
// Print
type Texter interface{ Text() string }
func (c Content) Print(texter Texter) { fmt.Println(c.Name, texter.Text()) }
// Excel
//
// Excel ストラテジー
type Excel struct {
excel int64 // excel のライブラリのデータを入れる
}
func (e Excel) Load() { fmt.Println("Excel load") }
func (e Excel) Text() string { return "Excel print done" + string(e.excel) }
// PDF
//
// PDF ストラテジー
type Pdf struct {
pdf string // pdf のライブラリのデータを入れる
}
func (p Pdf) Load() { fmt.Println("PDF load") }
func (p Pdf) Text() string { return "PDF print done" + p.pdf }
// Nil
//
// NullObject ストラテジー
type Nil struct{}
func (n Nil) Load() { fmt.Println("<Nil load>") } // noop
func (p Nil) Text() string { return "<Nil print done>" } // noop
所感
- Goだとおそらくメソッドインジェクションが多い印象
- Load / Print において、それぞれのInterfaceを切り出すこともできる
- またレイヤーが浅くなるのでシンプルになる
- ただ、今回の場合はexcel/pdfなどの情報を使い回すので Content の中に入れておけるコンストラクタインジェクションの方が良さそう