コードが複雑になる要因の一つとしてif文やswitch文による条件付きロジックがあります。以下のような給与を計算する実装例を考えてみます。(employeeType が文字列、という話はおいておきます)
switch 文があると呼び出し側の実装が複雑になります。switch 文を呼び出し元の実装からリファクタリングします。
- main.go
package main import "fmt" func main() { employeeType := "engineer" var amount int switch employeeType { case "engineer": amount = 1 case "salesman": amount = 10 default: amount = -1 } fmt.Println("amount", amount) }
TemplateMethodパターン
条件付きのロジックをSteragyパターンで置換する の記事ではStrategyパターンを使って呼び出し側の構造体にアルゴリズムを実装することができました。今回はTemplateMethodパターンで実装します。
Strategyパターンと本質的には同様で、TemplateMethodパターンでは抽象クラスやインターフェースを使って実装します。呼び出し元の main.go はStrategyパターンと変更はありません。
- model.go
package main type Employee interface { payAmount() int } func NewEmployee(employeeType string) Employee { switch employeeType { case "engineer": return Engineer{} case "salesman": return Salesman{} default: return dummy{} } } type Engineer struct{} func (e Engineer) payAmount() int { return 1 } type Salesman struct{} func (s Salesman) payAmount() int { return 10 } type dummy struct{} func (d dummy) payAmount() int { return -1 }
- main.go
package main import "fmt" func main() { e := NewEmployee("engineer") fmt.Println("amount", e.payAmount()) }
- 出力結果
$ go run . amount 1
呼び出し元からは Employee インターフェースのメソッドが呼び出されます。実装の詳細は Employee インターフェースを実装している各構造体のメソッドです。本例では Engineer 構造体のメソッドとなります。