goでデザインパターン

# builder
任意の項目を指定して構造体を初期化するパターン
各項目の関数では自身を返し、メソッドチェインで構造体を初期化していく。

```go
package main

type email struct {
	from, to, subject, body string
}
type EmailBuilder struct {
	email email
}
func (b *EmailBuilder) From(from string) *EmailBuilder {
	b.email.from = from
	return b
}
func (b *EmailBuilder) To(to string) *EmailBuilder {
	b.email.to = to
	return b
}
func (b *EmailBuilder) Subject(subject string) *EmailBuilder {
	b.email.subject = subject
	return b
}
func (b *EmailBuilder) Body(body string) *EmailBuilder {
	b.email.body = body
	return b
}
func sendMail(email *email) {
	// 実際の処理
}
type build func(*EmailBuilder)
func SendEmail(action build) {
	builder := EmailBuilder{}
	action(&builder)
	sendMail(&builder.email)
}
func main() {
	SendEmail(func(b *EmailBuilder) {
		b.From("hoge@example.com").
			To("huga@example.com").
			Subject("Sample").
			Body("HOGE")
	})
}
```

# functional builder
任意の項目を指定して構造体を初期化するパターン。
上述のbuilderパターンの関数バージョン。

```go

package main

type email struct {
	from, to, subject, body string
}

type EmailBuilder struct {
	email email
}

type Option func(b *EmailBuilder)

func From(from string) Option {
	return func(b *EmailBuilder) {
		b.email.from = from
	}
}
func To(to string) Option {
	return func(b *EmailBuilder) {
		b.email.to = to
	}
}
func Subject(subject string) Option {
	return func(b *EmailBuilder) {
		b.email.subject = subject
	}
}
func Body(body string) Option {
	return func(b *EmailBuilder) {
		b.email.body = body
	}
}
func sendMail(email *email) {
	// 実際の処理
}

func SendEmail(ops ...Option) {
	builder := EmailBuilder{}

	for _, option := range ops {
		option(&builder)
	}
	sendMail(&builder.email)
}

func main() {
	SendEmail(From("hoge@example.com"),
		To("huga@example.com"),
		Subject("Sample"),
		Body("HOGE"))
}
```

# functional builder2
任意の項目を指定して構造体を初期化するパターンその２。
ネストした構造体を初期化する。

```go
package main

import "fmt"

type User struct {
	id    int64
	skill *Skill
	item  *Item
}

func (u *User) Fetch(userId int64) func(u *User) {
	return func(u *User) {
		// データを取ってくる感じの処理
		// user := getUser(userId)
		u.id = userId
	}
}

type Skill struct {
	id     int64
	detail *SkillDetail
}

func (s *Skill) Fetch() func(u *User) {
	return func(u *User) {
		// データを取ってくる感じの処理
		// skill := getSkill(u.id)
		s.id = 1
	}
}

type Item struct {
	id int64
}

func (i *Item) Fetch() func(u *User) {
	return func(u *User) {
		// データを取ってくる感じの処理
		// item := getItem(u.id)
		i.id = 1
	}
}

type SkillDetail struct {
	atk int64
}

func (sd *SkillDetail) Fetch() func(u *User) {
	return func(u *User) {
		// データを取ってくる感じの処理
		// sd := getSkillDetail(u.skill.id)
		sd.atk = 1000
	}
}

func (u *User) Build(fetchLists ...func(u *User)) {
	for _, fetch := range fetchLists {
		fetch(u)
	}
}

func New(user *User) {
	user.Build(
		user.Fetch(1),
		user.skill.Fetch(),
		user.skill.detail.Fetch(),
		user.item.Fetch(),
	)

	fmt.Printf("%+v", user)
}

func main() {
	New(&User{
		skill: &Skill{
			detail: &SkillDetail{},
		},
		item: &Item{},
	})
}

```

# factory
構造体の初期化をfactoryに移譲するパターン。
各factoryで初期化される構造体は別物だが、同じような振る舞いを持つ構造体であれば、下記のようにinterfaceを利用し、createメソッドを抽象化すれば、疎結合にできる。

```go
package main

import "fmt"

type Employee struct {
	Name, Position string
}

func (e *Employee) setName(name string) {
	e.Name = name
}

type NewEmployeeFactory interface {
	create() *Employee
}

type DeveloperFactory struct {}
func (DeveloperFactory) create() *Employee {
	return &Employee{"", "Developer"}
}

type ManagerFactory struct {}
func (ManagerFactory) create() *Employee {
	return &Employee{"", "Manager"}
}

func NewEmployee(factory NewEmployeeFactory) *Employee {
	return factory.create()
}
func main() {
	developerFactory := DeveloperFactory{}
	dev := NewEmployee(developerFactory)
	dev.setName("Sam")
	managerFactory := ManagerFactory{}
	manager := NewEmployee(managerFactory)
	manager.setName("Bob")

	fmt.Println(dev)
	fmt.Println(manager)
}
```

# decorator
構造体にいろんな機能をデコレーションするかのように追加できるパターン。
構造体の中にinterfaceがあるのがポイント。interfaceを満たしていれば、デコレートし続けることができる

```go
package main
import "fmt"

type Shape interface {
	Render() string
}
type Circle struct {
	Radius float32
}
func (c *Circle) Render() string {
	return fmt.Sprintf("Circle of radius %f",
		c.Radius)
}

type ColoredShape struct {
	Shape Shape
	Color string
}
func (c *ColoredShape) Render() string {
	return fmt.Sprintf("%s has the color %s",
		c.Shape.Render(), c.Color)
}
type TransparentShape struct {
	Shape Shape
	Transparency float32
}
func (t *TransparentShape) Render() string {
	return fmt.Sprintf("%s has %f%% transparency",
		t.Shape.Render(), t.Transparency * 100.0)
}

func main() {
	circle := Circle{2}
	fmt.Println(circle.Render())
	redCircle := ColoredShape{&circle, "Red"}
	fmt.Println(redCircle.Render())
	rhsCircle := TransparentShape{&redCircle, 0.5}
	fmt.Println(rhsCircle.Render())
}
```

# state
状態を構造体として表すパターン。

- On/Offの状態を構造体で持つ。On構造体はOffメソッド、Off構造体はOnメソッドを実装している。
- Offの状態の時のOffメソッド、Onの状態の時のOnメソッドの実行は、BaseState構造体のOn/Offメソッドでカバー。
- 状態を構造体で表し、状態遷移をメソッドで表すことで、if文を使うことなく、stateを扱えている。

```golang
package main
import "fmt"

type Switch struct {
	State State
}
func NewSwitch() *Switch {
	return &Switch{NewOffState()}
}
func (s *Switch) On() {
	s.State.On(s)
}
func (s *Switch) Off() {
	s.State.Off(s)
}
type State interface {
	On(sw *Switch)
	Off(sw *Switch)
}
type BaseState struct {}
func (s *BaseState) On(sw *Switch) {
	fmt.Println("Light is already on")
}
func (s *BaseState) Off(sw *Switch) {
	fmt.Println("Light is already off")
}
type OnState struct {
	BaseState
}
func NewOnState() *OnState {
	fmt.Println("Light turned on")
	return &OnState{BaseState{}}
}
func (o *OnState) Off(sw *Switch) {
	fmt.Println("Turning light off...")
	sw.State = NewOffState()
}
type OffState struct {
	BaseState
}
func NewOffState() *OffState {
	fmt.Println("Light turned off")
	return &OffState{BaseState{}}
}
func (o *OffState) On(sw *Switch) {
	fmt.Println("Turning light on...")
	sw.State = NewOnState()
}
func main() {
	sw := NewSwitch()
	sw.On()
	sw.Off()
	sw.Off()
}
```

# strategy
機能の切り替えを容易にするパターン。
似たような機能が複数あったとして、その各機能のinterfaceを揃えてあげれば、具象的な処理を切り替えるだけでストラテジパターンが作れる。

- MarkdownListStrategy、HtmlListStrategyから生えてるメソッドでmarkdown、htmlの出力がされる。
- MarkdownListStrategy、HtmlListStrategyはListStrategyのinterfaceを満たしている。
- MarkdownListStrategy、HtmlListStrategyのどちらを使うかはSetOutputFormatで切り替えれる。
- AppendListメソッドでbufferに出力内容をためていく。二つのStrategyがListStrategyを満たしているため、ここの処理は共通化できる。

```go

package main
import (
	"fmt"
	"strings"
)
type OutputFormat int
const (
	Markdown OutputFormat = iota
	Html
)
type ListStrategy interface {
	Start(builder *strings.Builder)
	End(builder *strings.Builder)
	AddListItem(builder *strings.Builder, item string)
}
type MarkdownListStrategy struct {}
func (m *MarkdownListStrategy) Start(builder *strings.Builder) {}
func (m *MarkdownListStrategy) End(builder *strings.Builder) {}
func (m *MarkdownListStrategy) AddListItem(
	builder *strings.Builder, item string) {
	builder.WriteString(" * " + item + "\n")
}
type HtmlListStrategy struct {}
func (h *HtmlListStrategy) Start(builder *strings.Builder) {
	builder.WriteString("<ul>\n")
}
func (h *HtmlListStrategy) End(builder *strings.Builder) {
	builder.WriteString("</ul>\n")
}
func (h *HtmlListStrategy) AddListItem(builder *strings.Builder, item string) {
	builder.WriteString("  <li>" + item + "</li>\n")
}
type TextProcessor struct {
	builder strings.Builder
	listStrategy ListStrategy
}
func NewTextProcessor(listStrategy ListStrategy) *TextProcessor {
	return &TextProcessor{strings.Builder{}, listStrategy}
}
func (t *TextProcessor) SetOutputFormat(fmt OutputFormat) {
	switch fmt {
	case Markdown:
		t.listStrategy = &MarkdownListStrategy{}
	case Html:
		t.listStrategy = &HtmlListStrategy{}
	}
}
func (t *TextProcessor) AppendList(items []string) {
	t.listStrategy.Start(&t.builder)
	for _, item := range items {
		t.listStrategy.AddListItem(&t.builder, item)
	}
	t.listStrategy.End(&t.builder)
}
func (t *TextProcessor) Reset() {
	t.builder.Reset()
}
func (t *TextProcessor) String() string {
	return t.builder.String()
}
func main() {
	tp := NewTextProcessor(&MarkdownListStrategy{})
	tp.AppendList([]string{ "foo", "bar", "baz" })
	fmt.Println(tp)
	tp.Reset()
	tp.SetOutputFormat(Html)
	tp.AppendList([]string{ "foo", "bar", "baz" })
	fmt.Println(tp)
}
```

# proxy
処理の前にある処理を挟みたい場合のパターン。interfaceの差異の吸収だったり、バリデーションだったり。
実際に実行したいメソッド名とプロキシのメソッド名は合わせる。利用者側にはプロキシが挟まっていることを意識させない。

```golang

package proxy
import "fmt"

type Driven interface {
  Drive()
}
type Car struct {}
func (c *Car) Drive() {
  fmt.Println("Car being driven")
}
type Driver struct {
  Age int
}
type CarProxy struct {
  car Car
  driver *Driver
}
func (c *CarProxy) Drive() {
  if c.driver.Age >= 18 {
    c.car.Drive()
  } else {
    fmt.Println("Driver too young")
  }
}
func NewCarProxy(driver *Driver) *CarProxy {
  return &CarProxy{Car{}, driver}
}
func main() {
  car := NewCarProxy(&Driver{12})
  car.Drive()
}
```

# 再帰的な構造体
構造体の中にinterfaceを定義することで、再帰的な構造体が作れる。

- AdditionalExpressionとDoubleExpressionはleft/rightにExpressionのinterfaceを持つ。
- AdditionalExpressionとDoubleExpression自体がExpressionのinterfaceを満たしているので、left/rightを再帰的にすることができる

```golang

package main
import (
	"fmt"
	"strings"
)
type Expression interface {
	Print(sb *strings.Builder)
}
type DoubleExpression struct {
	value float64
}
func (d *DoubleExpression) Print(sb *strings.Builder) {
	sb.WriteString(fmt.Sprintf("%g", d.value))
}
type AdditionExpression struct {
	left, right Expression
}
func (a *AdditionExpression) Print(sb *strings.Builder) {
	sb.WriteString("(")
	a.left.Print(sb)
	sb.WriteString("+")
	a.right.Print(sb)
	sb.WriteString(")")
}
func main() {
	e := AdditionExpression{
		&DoubleExpression{1},
		&AdditionExpression{
			left:  &DoubleExpression{2},
			right: &DoubleExpression{3},
		},
	}
	sb := strings.Builder{}
	e.Print(&sb)
	fmt.Println(sb.String()) // 1+(2+3)
}
```