├── flyweight ├── flyweight_test.go └── flyweight.go ├── facade ├── facade_test.go └── facade.go ├── memento ├── memento_test.go └── memento.go ├── singleton └── singleton.go ├── prototype ├── prototype_test.go └── prototype.go ├── adapter ├── adapter_by_composition.go ├── adapter_test.go └── adapter_by_embedding.go ├── interpreter ├── interpreter_test.go └── interpreter.go ├── mediator ├── mediator_test.go └── mediator.go ├── decorator ├── decorator_test.go └── decorator.go ├── state ├── state_test.go └── state.go ├── observer ├── observer_test.go └── observer.go ├── singleton_use └── singleton_test.go ├── iterator ├── iterator_test.go └── iterator.go ├── factory_method ├── factory_method_test.go └── factory_method.go ├── strategy ├── strategy_test.go └── strategy.go ├── composite ├── composite_test.go └── composite.go ├── visitor ├── visitor_test.go └── visitor.go ├── command ├── command_test.go └── command.go ├── proxy ├── proxy_test.go └── proxy.go ├── template_method ├── template_method_test.go └── template_method.go ├── bridge ├── bridge_test.go └── bridge.go ├── abstract_factory ├── abstract_factory_test.go └── abstract_factory.go ├── chain_of_responsibility ├── chain_of_responsibility_test.go └── chain_of_responsibility.go ├── README_ENGLISH.md ├── README_PORTUGUES.md └── README.md /flyweight/flyweight_test.go: -------------------------------------------------------------------------------- 1 | package flyweight 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestFlyWeight(t *testing.T) { 8 | bigStr := NewBigString("121") 9 | result := bigStr.Print() 10 | 11 | expect := "-\n--\n-\n" 12 | if result != expect { 13 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /facade/facade_test.go: -------------------------------------------------------------------------------- 1 | package facade 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestFacade(t *testing.T) { 8 | maker := PageMaker{} 9 | result := maker.MakeWelcomePage("a@a.com") 10 | expect := "# Welcome to a's page!" 11 | 12 | if result != expect { 13 | t.Errorf("Expect result to equal %s, but %s.", expect, result) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /memento/memento_test.go: -------------------------------------------------------------------------------- 1 | package memento 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestMemento(t *testing.T) { 8 | 9 | game := &Game{100} 10 | memento := game.CreateMemento() 11 | 12 | game.Money = 0 13 | 14 | game.RestoreMemento(memento) 15 | 16 | if game.Money != 100 { 17 | t.Errorf("Expect money to equal %s, but %s\n", 100, game.Money) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /singleton/singleton.go: -------------------------------------------------------------------------------- 1 | package singleton 2 | 3 | // 構造体の名前を小文字にすることでパッケージ外へのエクスポートを行わない 4 | type singleton struct { 5 | } 6 | 7 | // インスタンスを保持する変数も小文字にすることでエクスポートを行わない 8 | var instance *singleton 9 | 10 | // インスタンス取得用の関数のみエクスポートしておき、ここでインスタンスが 11 | // 一意であることを保証する 12 | func GetInstance() *singleton { 13 | if instance == nil { 14 | instance = &singleton{} 15 | } 16 | return instance 17 | } 18 | -------------------------------------------------------------------------------- /prototype/prototype_test.go: -------------------------------------------------------------------------------- 1 | package prototype 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestPrototype(t *testing.T) { 8 | product := Product{"A"} 9 | product.SetUp() 10 | 11 | manager := Manager{} 12 | manager.Register(&product) 13 | 14 | cloned := manager.Create("A") 15 | 16 | if cloned.GetName() != product.GetName() { 17 | t.Errorf("Expect instance to equal, but not equal.") 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /memento/memento.go: -------------------------------------------------------------------------------- 1 | package memento 2 | 3 | type memento struct { 4 | money int 5 | } 6 | 7 | func (self *memento) getMoney() int { 8 | return self.money 9 | } 10 | 11 | type Game struct { 12 | Money int 13 | } 14 | 15 | func (self *Game) CreateMemento() *memento { 16 | return &memento{ 17 | self.Money, 18 | } 19 | } 20 | 21 | func (self *Game) RestoreMemento(memento *memento) { 22 | self.Money = memento.getMoney() 23 | } 24 | -------------------------------------------------------------------------------- /adapter/adapter_by_composition.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | type ComposiotionDecorateBanner struct { 4 | // 埋込ではなく構造体のフィールドとしてadapteeを保持 5 | banner *Banner 6 | } 7 | 8 | func NewCompositionDecorateBanner(str string) *ComposiotionDecorateBanner { 9 | return &ComposiotionDecorateBanner{&Banner{str}} 10 | } 11 | 12 | // インターフェースの実装と移譲によるアダプタ 13 | func (self *ComposiotionDecorateBanner) Decorate() string { 14 | return self.banner.getString() 15 | } 16 | -------------------------------------------------------------------------------- /interpreter/interpreter_test.go: -------------------------------------------------------------------------------- 1 | package interpreter 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestInterpreter(t *testing.T) { 8 | 9 | program := "program go right end" 10 | 11 | node := ProgramNode{} 12 | context := NewContext(program) 13 | node.Parse(context) 14 | 15 | expect := "program: go right " 16 | if node.ToString() != expect { 17 | t.Errorf("Expect result to equal %s, but %s.\n", expect, node.ToString()) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /mediator/mediator_test.go: -------------------------------------------------------------------------------- 1 | package mediator 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestMediator(t *testing.T) { 8 | loginForm := NewLoginForm() 9 | 10 | state := loginForm.Button.Enabled 11 | if state { 12 | t.Errorf("Expect state to false, but true.\n") 13 | } 14 | 15 | loginForm.RadioButton.Check(true) 16 | 17 | state = loginForm.Button.Enabled 18 | if !state { 19 | t.Errorf("Expect state to true, but false.\n") 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /decorator/decorator_test.go: -------------------------------------------------------------------------------- 1 | package decorator 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestDecorator(t *testing.T) { 8 | d1 := NewStringDisplay("A") 9 | result := d1.Show(d1) 10 | 11 | if result != "A" { 12 | t.Errorf("Expect result to equal %s, but %s.\n", "A", result) 13 | } 14 | 15 | d2 := NewSideBorder(d1, "|") 16 | result = d2.Show(d2) 17 | 18 | if result != "|A|" { 19 | t.Errorf("Expect result to equal %s, but %s.\n", "|A|", result) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /state/state_test.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestState(t *testing.T) { 8 | 9 | safeFrame := &SafeFrame{State: GetDayInstance()} 10 | 11 | hours := []int{8, 9, 16, 17} 12 | 13 | for _, hour := range hours { 14 | safeFrame.SetClock(hour) 15 | safeFrame.Use() 16 | } 17 | 18 | expect := "night day day night" 19 | if safeFrame.GetLog() != expect { 20 | t.Errorf("Expect log to equal %s, but %s\n", expect, safeFrame.GetLog()) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /observer/observer_test.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestObserver(t *testing.T) { 8 | 9 | random := NewRandomNumberGenerator() 10 | 11 | o1 := &DigitObserver{random} 12 | o2 := &DigitObserver{random} 13 | 14 | random.AddObserver(o1) 15 | random.AddObserver(o2) 16 | 17 | result := random.Execute() 18 | 19 | for _, r := range result { 20 | if len(result) != 2 && r >= 50 { 21 | t.Errorf("Expect result to equal random int array") 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /singleton_use/singleton_test.go: -------------------------------------------------------------------------------- 1 | package use_singleton 2 | 3 | import ( 4 | "github.com/monochromegane/go_design_pattern/singleton" 5 | "testing" 6 | ) 7 | 8 | func TestSingleton(t *testing.T) { 9 | 10 | // cannot refer to unexported name singleton.singleton 11 | // instance := singleton.singleton{} 12 | 13 | instance1 := singleton.GetInstance() 14 | instance2 := singleton.GetInstance() 15 | 16 | if instance1 != instance2 { 17 | t.Errorf("Expect instance to equal, but not equal.\n") 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /iterator/iterator_test.go: -------------------------------------------------------------------------------- 1 | package iterator 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestIterator(t *testing.T) { 8 | bookShelf := &BookShelf{} 9 | 10 | asserts := []string{"A", "B", "C"} 11 | 12 | for _, assert := range asserts { 13 | bookShelf.Add(&Book{assert}) 14 | } 15 | 16 | i := 0 17 | for iterator := bookShelf.Iterator(); iterator.HasNext(); { 18 | if book := iterator.Next(); book.(*Book).name != asserts[i] { 19 | t.Errorf("Expect Book.name to %s, but %s", asserts[i], book.(*Book).name) 20 | } 21 | i++ 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /factory_method/factory_method_test.go: -------------------------------------------------------------------------------- 1 | package factory_method 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestFactoryMethod(t *testing.T) { 8 | 9 | assert := []string{"A", "B", "C"} 10 | 11 | factory := &IDCardFactory{} 12 | products := []User{ 13 | factory.Create(factory, "A"), 14 | factory.Create(factory, "B"), 15 | factory.Create(factory, "C"), 16 | } 17 | 18 | for i, product := range products { 19 | if owner := product.Use(); owner != assert[i] { 20 | t.Errorf("Expect owner to %s, but %s.\n", assert[i], owner) 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /strategy/strategy_test.go: -------------------------------------------------------------------------------- 1 | package strategy 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestStrategy(t *testing.T) { 8 | player1 := Player{Name: "A", Strategy: &winningStrategy{seed: 10}} 9 | player2 := Player{Name: "B", Strategy: &winningStrategy{seed: 20}} 10 | 11 | hand1 := player1.NextHand() 12 | hand2 := player2.NextHand() 13 | 14 | if hand1.IsStrongerThan(hand2) { 15 | player1.Win() 16 | player2.Lose() 17 | } else if hand1.IsWeakerThan(hand2) { 18 | player1.Lose() 19 | player2.Win() 20 | } else { 21 | player1.Even() 22 | player2.Even() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /composite/composite_test.go: -------------------------------------------------------------------------------- 1 | package composite 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestComposite(t *testing.T) { 8 | 9 | rootDir := NewDirectory("root") 10 | usrDir := NewDirectory("usr") 11 | fileA := NewFile("A", 1) 12 | 13 | rootDir.Add(usrDir) 14 | rootDir.Add(fileA) 15 | 16 | fileB := NewFile("B", 2) 17 | usrDir.Add(fileB) 18 | 19 | result := rootDir.PrintList("") 20 | 21 | expect := "/root (3)\n/root/usr (2)\n/root/usr/B (2)\n/root/A (1)\n" 22 | if result != expect { 23 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /visitor/visitor_test.go: -------------------------------------------------------------------------------- 1 | package visitor 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestComposite(t *testing.T) { 8 | 9 | rootDir := NewDirectory("root") 10 | usrDir := NewDirectory("usr") 11 | fileA := NewFile("A", 1) 12 | 13 | rootDir.Add(usrDir) 14 | rootDir.Add(fileA) 15 | 16 | fileB := NewFile("B", 2) 17 | usrDir.Add(fileB) 18 | 19 | result := rootDir.Accept(&listVisitor{}) 20 | 21 | expect := "/root (3)\n/root/usr (2)\n/root/usr/B (2)\n/root/A (1)\n" 22 | if result != expect { 23 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /command/command_test.go: -------------------------------------------------------------------------------- 1 | package command 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestCommand(t *testing.T) { 8 | 9 | macro := MacroCommand{} 10 | 11 | macro.Append(&DrawCommand{&Position{1, 1}}) 12 | macro.Append(&DrawCommand{&Position{2, 2}}) 13 | 14 | expect := "1.1\n2.2\n" 15 | if macro.Execute() != expect { 16 | t.Errorf("Expect result to equal %s, but %s.\n", expect, macro.Execute()) 17 | } 18 | 19 | macro.Undo() 20 | expect = "1.1\n" 21 | if macro.Execute() != expect { 22 | t.Errorf("Expect result to equal %s, but %s.\n", expect, macro.Execute()) 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /proxy/proxy_test.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestProxy(t *testing.T) { 8 | proxy := PrinterProxy{Name: "A"} 9 | name := proxy.GetPrinterName() 10 | 11 | if name != "A" { 12 | t.Errorf("Expect name to equal %s, but %s.\n", "A", name) 13 | } 14 | 15 | proxy.SetPrinterName("B") 16 | name = proxy.GetPrinterName() 17 | if name != "B" { 18 | t.Errorf("Expect name to equal %s, but %s.\n", "B", name) 19 | } 20 | 21 | result := proxy.Print("C") 22 | if result != "B:C" { 23 | t.Errorf("Expect result to equal %s, but %s.\n", "B:C", result) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /adapter/adapter_test.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestAdapterByEmbedded(t *testing.T) { 8 | var decorator Decorator 9 | 10 | decorator = NewEmbeddedDecorateBanner("A") 11 | 12 | if str := decorator.Decorate(); str != "*A*" { 13 | t.Errorf("Expect decorated str to %s, but %s", "*A*", str) 14 | } 15 | 16 | } 17 | 18 | func TestAdapterByDelegate(t *testing.T) { 19 | var decorator Decorator 20 | 21 | decorator = NewCompositionDecorateBanner("A") 22 | 23 | if str := decorator.Decorate(); str != "*A*" { 24 | t.Errorf("Expect decorated str to %s, but %s", "*A*", str) 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /template_method/template_method_test.go: -------------------------------------------------------------------------------- 1 | package template_method 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestCharDisplay(t *testing.T) { 8 | display := &CharDisplay{Char: 'A'} 9 | result := display.Display(display) 10 | if result != "<>" { 11 | t.Errorf("Expect result to %s, but %s.\n", "<>", result) 12 | } 13 | } 14 | 15 | func TestStringDisplay(t *testing.T) { 16 | expect := "+-------+\n| ABCDE |\n| ABCDE |\n| ABCDE |\n| ABCDE |\n| ABCDE |\n+-------+\n" 17 | display := &StringDisplay{Str: "ABCDE"} 18 | result := display.Display(display) 19 | if result != expect { 20 | t.Errorf("Expect result to \n%s, but \n%s.\n", expect, result) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /facade/facade.go: -------------------------------------------------------------------------------- 1 | package facade 2 | 3 | var db = map[string]string{ 4 | "a@a.com": "a", 5 | "b@b.com": "b", 6 | } 7 | 8 | type database struct { 9 | } 10 | 11 | func (self *database) getNameByMail(mail string) string { 12 | return db[mail] 13 | } 14 | 15 | type mdWriter struct { 16 | } 17 | 18 | func (self *mdWriter) title(title string) string { 19 | return "# Welcome to " + title + "'s page!" 20 | } 21 | 22 | type PageMaker struct { 23 | } 24 | 25 | func (self *PageMaker) MakeWelcomePage(mail string) string { 26 | database := database{} 27 | writer := mdWriter{} 28 | 29 | name := database.getNameByMail(mail) 30 | page := writer.title(name) 31 | 32 | return page 33 | } 34 | -------------------------------------------------------------------------------- /adapter/adapter_by_embedding.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | type Decorator interface { 4 | Decorate() string 5 | } 6 | 7 | type Banner struct { 8 | str string 9 | } 10 | 11 | func (self *Banner) getString() string { 12 | return "*" + self.str + "*" 13 | } 14 | 15 | // 構造体の埋込による継承 16 | type EmbeddedDecorateBanner struct { 17 | *Banner 18 | } 19 | 20 | // 埋込による継承はgetは構造体の階層を意識しなくてもよいが 21 | // setは明示的に埋め込んだ構造体に明示的に値を定義する必要があるため、 22 | // 呼び出し側が階層を意識しなくてもよいようにラップするなど工夫が必要 23 | func NewEmbeddedDecorateBanner(str string) *EmbeddedDecorateBanner { 24 | return &EmbeddedDecorateBanner{&Banner{str}} 25 | } 26 | 27 | // インターフェースの実装と埋め込んだ構造体のメソッドによるアダプタ 28 | func (self *EmbeddedDecorateBanner) Decorate() string { 29 | return self.getString() 30 | } 31 | -------------------------------------------------------------------------------- /bridge/bridge_test.go: -------------------------------------------------------------------------------- 1 | package bridge 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestBridge(t *testing.T) { 8 | 9 | d1 := DefaultDisplay{&StringDisplayImpl{"AAA"}} 10 | expect := "+---+\n|AAA|\n+---+\n" 11 | if result := d1.Display(); result != expect { 12 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result) 13 | } 14 | 15 | d2 := CountDisplay{&DefaultDisplay{&StringDisplayImpl{"BBB"}}} 16 | expect = "+---+\n|BBB|\n+---+\n" 17 | if result := d2.Display(); result != expect { 18 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result) 19 | } 20 | 21 | expect = "+---+\n|BBB|\n|BBB|\n+---+\n" 22 | if result := d2.MultiDisplay(2); result != expect { 23 | t.Errorf("Expect result to equal %s, but %s.\n", expect, result) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /abstract_factory/abstract_factory_test.go: -------------------------------------------------------------------------------- 1 | package abstract_factory 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestAbstractFactory(t *testing.T) { 8 | 9 | factory := MdFactory{} 10 | 11 | usYahoo := factory.CreateLink("Yahoo!", "http://www.yahoo.com") 12 | jaYahoo := factory.CreateLink("Yahoo!Japan", "http://www.yahoo.co.jp") 13 | 14 | tray := factory.CreateTray("Yahoo!") 15 | tray.AddToTray(usYahoo) 16 | tray.AddToTray(jaYahoo) 17 | 18 | page := factory.CreatePage("Title", "Author") 19 | page.AddToContent(tray) 20 | 21 | output := page.Output() 22 | 23 | expect := "title: Title\nauthor: Author\n- Yahoo!\n[Yahoo!](http://www.yahoo.com)\n[Yahoo!Japan](http://www.yahoo.co.jp)\n\n" 24 | 25 | if output != expect { 26 | t.Errorf("Expect output to %s, but %s\n", expect, output) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /prototype/prototype.go: -------------------------------------------------------------------------------- 1 | package prototype 2 | 3 | type producter interface { 4 | clone() producter 5 | GetName() string 6 | } 7 | 8 | type Manager struct { 9 | product producter 10 | } 11 | 12 | func (self *Manager) Register(producter producter) { 13 | self.product = producter 14 | } 15 | 16 | func (self *Manager) Create(name string) producter { 17 | producter := self.product 18 | return producter.clone() 19 | } 20 | 21 | type Product struct { 22 | name string 23 | } 24 | 25 | func (self *Product) SetUp() { 26 | // something takes time... 27 | } 28 | 29 | func (self *Product) GetName() string { 30 | return self.name 31 | } 32 | 33 | // 新しい構造体に自身の値をセットして返すことで擬似的にcloneとした。 34 | // ポインタ参照まで考慮したdeepcopyに関しては実装もしくは機能を提供する 35 | // パッケージが必要になる 36 | func (self *Product) clone() producter { 37 | return &Product{self.name} 38 | } 39 | -------------------------------------------------------------------------------- /chain_of_responsibility/chain_of_responsibility_test.go: -------------------------------------------------------------------------------- 1 | package chain_of_responsibility 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestChainOfResponsibility(t *testing.T) { 8 | a := NewNoSupport("A") 9 | b := NewLimitSupport("B", 2) 10 | c := NewLimitSupport("C", 3) 11 | a.SetNext(b) 12 | b.SetNext(c) 13 | 14 | result := a.Handle(a, Trouble{1}) 15 | expect := "trouble:1 is resolved by B" 16 | if result != expect { 17 | t.Errorf("Expect result to be equal %s, but %s\n", expect, result) 18 | } 19 | 20 | result = a.Handle(a, Trouble{2}) 21 | expect = "trouble:2 is resolved by C" 22 | if result != expect { 23 | t.Errorf("Expect result to be equal %s, but %s\n", expect, result) 24 | } 25 | 26 | result = a.Handle(a, Trouble{3}) 27 | expect = "trouble:3 cannot be resolved" 28 | if result != expect { 29 | t.Errorf("Expect result to be equal %s, but %s\n", expect, result) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /command/command.go: -------------------------------------------------------------------------------- 1 | package command 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | type command interface { 8 | Execute() string 9 | } 10 | 11 | type MacroCommand struct { 12 | commands []command 13 | } 14 | 15 | func (self *MacroCommand) Execute() string { 16 | var result string 17 | for _, command := range self.commands { 18 | result += command.Execute() + "\n" 19 | } 20 | return result 21 | } 22 | 23 | func (self *MacroCommand) Append(command command) { 24 | self.commands = append(self.commands, command) 25 | } 26 | 27 | func (self *MacroCommand) Undo() { 28 | if len(self.commands) != 0 { 29 | self.commands = self.commands[:len(self.commands)-1] 30 | } 31 | } 32 | 33 | func (self *MacroCommand) Clear() { 34 | self.commands = []command{} 35 | } 36 | 37 | type Position struct { 38 | X, Y int 39 | } 40 | 41 | type DrawCommand struct { 42 | Position *Position 43 | } 44 | 45 | func (self *DrawCommand) Execute() string { 46 | return strconv.Itoa(self.Position.X) + "." + strconv.Itoa(self.Position.Y) 47 | } 48 | -------------------------------------------------------------------------------- /proxy/proxy.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | type printable interface { 4 | SetPrinterName(name string) 5 | GetPrinterName() string 6 | Print(str string) string 7 | } 8 | 9 | type printer struct { 10 | name string 11 | } 12 | 13 | func (self *printer) SetPrinterName(name string) { 14 | self.name = name 15 | } 16 | 17 | func (self *printer) GetPrinterName() string { 18 | return self.name 19 | } 20 | 21 | func (self *printer) Print(str string) string { 22 | return self.name + ":" + str 23 | } 24 | 25 | type PrinterProxy struct { 26 | Name string 27 | real *printer 28 | } 29 | 30 | func (self *PrinterProxy) SetPrinterName(name string) { 31 | if self.real != nil { 32 | self.real.SetPrinterName(name) 33 | } 34 | self.Name = name 35 | } 36 | 37 | func (self *PrinterProxy) GetPrinterName() string { 38 | return self.Name 39 | } 40 | 41 | func (self *PrinterProxy) Print(str string) string { 42 | self.realize() 43 | return self.real.Print(str) 44 | } 45 | 46 | func (self *PrinterProxy) realize() { 47 | if self.real == nil { 48 | self.real = &printer{self.Name} 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /iterator/iterator.go: -------------------------------------------------------------------------------- 1 | package iterator 2 | 3 | type Aggregate interface { 4 | Iterator() Iterator 5 | } 6 | 7 | type Iterator interface { 8 | HasNext() bool 9 | Next() interface{} 10 | } 11 | 12 | type BookShelf struct { 13 | Books []*Book 14 | } 15 | 16 | func (self *BookShelf) Add(book *Book) { 17 | self.Books = append(self.Books, book) 18 | } 19 | 20 | // *Iterator is pointer to interface, not interface 21 | // - Iteratorのポインタはインターフェースでないのでポインタではなくインターフェースとして戻り値を定義する 22 | // - ポインタをレシーバーとしてインターフェースメソッドを実装しているのでIteratorの具象はポインタとして返さなければ実装したとみなされない 23 | func (self *BookShelf) Iterator() Iterator { 24 | return &BookShelfIterator{BookShelf: self} 25 | } 26 | 27 | type BookShelfIterator struct { 28 | BookShelf *BookShelf 29 | last int 30 | } 31 | 32 | func (self *BookShelfIterator) HasNext() bool { 33 | if self.last >= len(self.BookShelf.Books) { 34 | return false 35 | } 36 | return true 37 | } 38 | 39 | func (self *BookShelfIterator) Next() interface{} { 40 | book := self.BookShelf.Books[self.last] 41 | self.last++ 42 | return book 43 | } 44 | 45 | type Book struct { 46 | name string 47 | } 48 | -------------------------------------------------------------------------------- /observer/observer.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "math/rand" 5 | ) 6 | 7 | type numberGenerator struct { 8 | observers []observer 9 | } 10 | 11 | func (self *numberGenerator) AddObserver(observer observer) { 12 | self.observers = append(self.observers, observer) 13 | } 14 | 15 | func (self *numberGenerator) notifyObservers() []int { 16 | var result []int 17 | for _, observer := range self.observers { 18 | result = append(result, observer.update()) 19 | } 20 | return result 21 | } 22 | 23 | type randomNumberGenerator struct { 24 | *numberGenerator 25 | } 26 | 27 | func NewRandomNumberGenerator() *randomNumberGenerator { 28 | return &randomNumberGenerator{&numberGenerator{}} 29 | } 30 | 31 | type number interface { 32 | getNumber() int 33 | } 34 | 35 | func (self *randomNumberGenerator) getNumber() int { 36 | return rand.Intn(50) 37 | } 38 | 39 | func (self *randomNumberGenerator) Execute() []int { 40 | return self.notifyObservers() 41 | } 42 | 43 | type observer interface { 44 | update() int 45 | } 46 | 47 | type DigitObserver struct { 48 | generator number 49 | } 50 | 51 | func (self *DigitObserver) update() int { 52 | return self.generator.getNumber() 53 | } 54 | -------------------------------------------------------------------------------- /bridge/bridge.go: -------------------------------------------------------------------------------- 1 | package bridge 2 | 3 | type DisplayImpl interface { 4 | rawOpen() string 5 | rawPrint() string 6 | rawClose() string 7 | } 8 | 9 | type StringDisplayImpl struct { 10 | str string 11 | } 12 | 13 | func (self *StringDisplayImpl) rawOpen() string { 14 | return self.printLine() 15 | } 16 | 17 | func (self *StringDisplayImpl) rawPrint() string { 18 | return "|" + self.str + "|\n" 19 | } 20 | 21 | func (self *StringDisplayImpl) rawClose() string { 22 | return self.printLine() 23 | } 24 | 25 | func (self *StringDisplayImpl) printLine() string { 26 | str := "+" 27 | for _, _ = range self.str { 28 | str += string("-") 29 | } 30 | str += "+\n" 31 | return str 32 | } 33 | 34 | type DefaultDisplay struct { 35 | impl DisplayImpl 36 | } 37 | 38 | func (self *DefaultDisplay) open() string { 39 | return self.impl.rawOpen() 40 | } 41 | 42 | func (self *DefaultDisplay) print() string { 43 | return self.impl.rawPrint() 44 | } 45 | 46 | func (self *DefaultDisplay) close() string { 47 | return self.impl.rawClose() 48 | } 49 | 50 | func (self *DefaultDisplay) Display() string { 51 | return self.open() + 52 | self.print() + 53 | self.close() 54 | } 55 | 56 | type CountDisplay struct { 57 | *DefaultDisplay 58 | } 59 | 60 | func (self *CountDisplay) MultiDisplay(num int) string { 61 | str := self.open() 62 | for i := 0; i < num; i++ { 63 | str += self.print() 64 | } 65 | str += self.close() 66 | return str 67 | } 68 | -------------------------------------------------------------------------------- /factory_method/factory_method.go: -------------------------------------------------------------------------------- 1 | package factory_method 2 | 3 | type creater interface { 4 | createProduct(owner string) User 5 | registerProduct(User) 6 | } 7 | 8 | type User interface { 9 | Use() string 10 | } 11 | 12 | type Factory struct { 13 | } 14 | 15 | // インスタンス生成部分にはTemplateMethodパターンを使う。 16 | // Goではclient-specified self patternにより親構造体のメソッド内で子構造体の 17 | // 実装を呼ぶことができる 18 | // 19 | // 処理の流れが簡易でテンプレートを使わないでよければ、ファクトリとなる関数を 20 | // 直接引数に渡してもよい 21 | // この場合、個別のファクトリークラスを定義しなくてもよくなる。 22 | // func (self *Factory) Create(factoryMethod func() User) { 23 | // self.product = factoryMethod() 24 | // return self.product 25 | // } 26 | func (self *Factory) Create(factory creater, owner string) User { 27 | user := factory.createProduct(owner) 28 | factory.registerProduct(user) 29 | return user 30 | } 31 | 32 | // 本来であれば基底クラスによるポリモフィズムを用いるが、Goの埋込による 33 | // 構造体では機能しない。この例では親構造体に共通処理がないため、インターフェースの 34 | // 実装によるポリモフィズムを実現する。 35 | // よって基底クラスを定義する必要はない。 36 | // 37 | // type Product struct { 38 | // } 39 | 40 | type IDCard struct { 41 | owner string 42 | } 43 | 44 | func (self *IDCard) Use() string { 45 | return self.owner 46 | } 47 | 48 | type IDCardFactory struct { 49 | *Factory 50 | owners []*string 51 | } 52 | 53 | func (self *IDCardFactory) createProduct(owner string) User { 54 | return &IDCard{owner} 55 | } 56 | 57 | func (self *IDCardFactory) registerProduct(product User) { 58 | owner := product.Use() 59 | self.owners = append(self.owners, &owner) 60 | } 61 | -------------------------------------------------------------------------------- /mediator/mediator.go: -------------------------------------------------------------------------------- 1 | package mediator 2 | 3 | type mediator interface { 4 | createColleagues() 5 | colleagueChanged() 6 | } 7 | 8 | type colleague interface { 9 | setMediator(mediator mediator) 10 | setColleagueEnabled(enabled bool) 11 | } 12 | 13 | type button struct { 14 | Enabled bool 15 | mediator mediator 16 | } 17 | 18 | func (self *button) setMediator(mediator mediator) { 19 | self.mediator = mediator 20 | } 21 | 22 | func (self *button) setColleagueEnabled(enabled bool) { 23 | self.Enabled = enabled 24 | } 25 | 26 | type radioButton struct { 27 | enabled bool 28 | checked bool 29 | mediator mediator 30 | } 31 | 32 | func (self *radioButton) setMediator(mediator mediator) { 33 | self.mediator = mediator 34 | } 35 | 36 | func (self *radioButton) setColleagueEnabled(enabled bool) { 37 | self.enabled = enabled 38 | } 39 | 40 | func (self *radioButton) Check(checked bool) { 41 | self.checked = checked 42 | self.mediator.colleagueChanged() 43 | } 44 | 45 | type loginForm struct { 46 | RadioButton radioButton 47 | Button button 48 | } 49 | 50 | func NewLoginForm() *loginForm { 51 | loginForm := &loginForm{} 52 | loginForm.createColleagues() 53 | return loginForm 54 | } 55 | 56 | func (self *loginForm) createColleagues() { 57 | self.RadioButton = radioButton{} 58 | self.Button = button{} 59 | self.RadioButton.setMediator(self) 60 | self.Button.setMediator(self) 61 | } 62 | 63 | func (self *loginForm) colleagueChanged() { 64 | if !self.RadioButton.checked { 65 | self.Button.setColleagueEnabled(false) 66 | } else { 67 | self.Button.setColleagueEnabled(true) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /flyweight/flyweight.go: -------------------------------------------------------------------------------- 1 | package flyweight 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | type bigChar struct { 8 | charName string 9 | fontData string 10 | } 11 | 12 | func NewBigChar(charName string) *bigChar { 13 | char := &bigChar{charName: charName} 14 | char.loadFontData() 15 | return char 16 | } 17 | 18 | func (self *bigChar) loadFontData() { 19 | num, _ := strconv.Atoi(self.charName) 20 | var str string 21 | for i := 0; i < num; i++ { 22 | str += "-" 23 | } 24 | self.fontData = str 25 | } 26 | 27 | func (self *bigChar) Print() string { 28 | return self.fontData 29 | } 30 | 31 | var instance *bigCharFactory 32 | 33 | type bigCharFactory struct { 34 | pool map[string]*bigChar 35 | } 36 | 37 | func GetBigCharFactory() *bigCharFactory { 38 | if instance == nil { 39 | instance = &bigCharFactory{} 40 | } 41 | return instance 42 | } 43 | 44 | func (self *bigCharFactory) getBigChar(charName string) *bigChar { 45 | if self.pool == nil { 46 | self.pool = make(map[string]*bigChar) 47 | } 48 | if _, ok := self.pool[charName]; !ok { 49 | self.pool[charName] = NewBigChar(charName) 50 | } 51 | return self.pool[charName] 52 | } 53 | 54 | type bigString struct { 55 | bigChars []*bigChar 56 | } 57 | 58 | func NewBigString(str string) *bigString { 59 | bigStr := &bigString{} 60 | factory := GetBigCharFactory() 61 | 62 | for _, s := range str { 63 | bigStr.bigChars = append(bigStr.bigChars, factory.getBigChar(string(s))) 64 | } 65 | return bigStr 66 | } 67 | 68 | func (self *bigString) Print() string { 69 | var result string 70 | for _, s := range self.bigChars { 71 | result += s.Print() + "\n" 72 | } 73 | return result 74 | } 75 | -------------------------------------------------------------------------------- /decorator/decorator.go: -------------------------------------------------------------------------------- 1 | package decorator 2 | 3 | type display interface { 4 | getColumns() int 5 | getRows() int 6 | getRowText(row int) string 7 | Show(display display) string 8 | } 9 | 10 | type defaultDisplay struct { 11 | display 12 | } 13 | 14 | func (self *defaultDisplay) Show(display display) string { 15 | str := "" 16 | for i := 0; i < display.getRows(); i++ { 17 | str += display.getRowText(i) 18 | } 19 | return str 20 | } 21 | 22 | type StringDisplay struct { 23 | *defaultDisplay 24 | str string 25 | } 26 | 27 | func NewStringDisplay(str string) *StringDisplay { 28 | return &StringDisplay{ 29 | &defaultDisplay{}, 30 | str, 31 | } 32 | } 33 | 34 | func (self *StringDisplay) getColumns() int { 35 | return len(self.str) 36 | } 37 | 38 | func (self *StringDisplay) getRows() int { 39 | return 1 40 | } 41 | 42 | func (self *StringDisplay) getRowText(row int) string { 43 | if row == 0 { 44 | return self.str 45 | } else { 46 | return "" 47 | } 48 | } 49 | 50 | type border struct { 51 | *defaultDisplay 52 | display display 53 | } 54 | 55 | type SideBorder struct { 56 | *border 57 | borderChar string 58 | } 59 | 60 | func NewSideBorder(display display, borderChar string) *SideBorder { 61 | return &SideBorder{ 62 | &border{display: display}, 63 | borderChar, 64 | } 65 | } 66 | 67 | func (self *SideBorder) getColumns() int { 68 | return len(self.borderChar)*2 + self.display.getColumns() 69 | } 70 | 71 | func (self *SideBorder) getRows() int { 72 | return self.display.getRows() 73 | } 74 | 75 | func (self *SideBorder) getRowText(row int) string { 76 | return self.borderChar + self.display.getRowText(row) + self.borderChar 77 | } 78 | -------------------------------------------------------------------------------- /composite/composite.go: -------------------------------------------------------------------------------- 1 | package composite 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | type entry interface { 8 | getName() string 9 | getSize() int 10 | PrintList(prefix string) string 11 | Add(entry entry) 12 | } 13 | 14 | type defaultEntry struct { 15 | entry 16 | name string 17 | } 18 | 19 | func (self *defaultEntry) getName() string { 20 | return self.name 21 | } 22 | 23 | func (self *defaultEntry) print(entry entry) string { 24 | return entry.getName() + " (" + strconv.Itoa(entry.getSize()) + ")\n" 25 | } 26 | 27 | type file struct { 28 | *defaultEntry 29 | size int 30 | } 31 | 32 | func (self *file) getSize() int { 33 | return self.size 34 | } 35 | 36 | func (self *file) PrintList(prefix string) string { 37 | return prefix + "/" + self.print(self) 38 | } 39 | 40 | func (self *file) Add(entry entry) {} 41 | 42 | type directory struct { 43 | *defaultEntry 44 | dir []entry 45 | } 46 | 47 | func (self *directory) getSize() int { 48 | size := 0 49 | for _, dir := range self.dir { 50 | size += dir.getSize() 51 | } 52 | return size 53 | } 54 | 55 | func (self *directory) Add(entry entry) { 56 | self.dir = append(self.dir, entry) 57 | } 58 | 59 | func (self *directory) PrintList(prefix string) string { 60 | list := prefix + "/" + self.print(self) 61 | for _, dir := range self.dir { 62 | list += dir.PrintList(prefix + "/" + self.getName()) 63 | } 64 | return list 65 | } 66 | 67 | // 利用側に埋込構造体を意識させないためのインスタンス生成関数。 68 | func NewFile(name string, size int) *file { 69 | return &file{ 70 | defaultEntry: &defaultEntry{name: name}, // 埋込時のキーには構造体と同名のものを使うことができる 71 | size: size, 72 | } 73 | } 74 | func NewDirectory(name string) *directory { 75 | return &directory{defaultEntry: &defaultEntry{name: name}} 76 | } 77 | -------------------------------------------------------------------------------- /state/state.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | type state interface { 8 | doClock(context context, hour int) 9 | doUse(context context) 10 | } 11 | 12 | var dayInstance *dayState 13 | 14 | type dayState struct { 15 | } 16 | 17 | func GetDayInstance() *dayState { 18 | if dayInstance == nil { 19 | dayInstance = &dayState{} 20 | } 21 | return dayInstance 22 | } 23 | 24 | func (self *dayState) doClock(context context, hour int) { 25 | if hour < 9 || 17 <= hour { 26 | context.changeState(GetNightInstance()) 27 | } 28 | } 29 | 30 | func (self *dayState) doUse(context context) { 31 | context.recordLog("day") 32 | } 33 | 34 | var nightInstance *nightState 35 | 36 | type nightState struct { 37 | } 38 | 39 | func GetNightInstance() *nightState { 40 | if nightInstance == nil { 41 | nightInstance = &nightState{} 42 | } 43 | return nightInstance 44 | } 45 | 46 | func (self *nightState) doClock(context context, hour int) { 47 | if 9 <= hour && hour < 17 { 48 | context.changeState(GetDayInstance()) 49 | } 50 | } 51 | 52 | func (self *nightState) doUse(context context) { 53 | context.recordLog("night") 54 | } 55 | 56 | type context interface { 57 | SetClock(hour int) 58 | changeState(state state) 59 | recordLog(log string) 60 | } 61 | 62 | type SafeFrame struct { 63 | State state 64 | logs []string 65 | } 66 | 67 | func (self *SafeFrame) SetClock(hour int) { 68 | self.State.doClock(self, hour) 69 | } 70 | 71 | func (self *SafeFrame) changeState(state state) { 72 | self.State = state 73 | } 74 | 75 | func (self *SafeFrame) recordLog(log string) { 76 | self.logs = append(self.logs, log) 77 | } 78 | 79 | func (self *SafeFrame) Use() { 80 | self.State.doUse(self) 81 | } 82 | 83 | func (self *SafeFrame) GetLog() string { 84 | return strings.Join(self.logs, " ") 85 | } 86 | -------------------------------------------------------------------------------- /chain_of_responsibility/chain_of_responsibility.go: -------------------------------------------------------------------------------- 1 | package chain_of_responsibility 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | type Trouble struct { 8 | number int 9 | } 10 | 11 | func (self *Trouble) getNumber() int { 12 | return self.number 13 | } 14 | 15 | type support interface { 16 | resolve(trouble Trouble) bool 17 | Handle(support support, trouble Trouble) string 18 | } 19 | 20 | type defaultSupport struct { 21 | support 22 | name string 23 | next support 24 | } 25 | 26 | func (self *defaultSupport) SetNext(next support) { 27 | self.next = next 28 | } 29 | 30 | func (self *defaultSupport) Handle(support support, trouble Trouble) string { 31 | if support.resolve(trouble) { 32 | return self.done(trouble) 33 | } else if self.next != nil { 34 | return self.next.Handle(self.next, trouble) 35 | } else { 36 | return self.fail(trouble) 37 | } 38 | } 39 | 40 | func (self *defaultSupport) done(trouble Trouble) string { 41 | return "trouble:" + strconv.Itoa(trouble.getNumber()) + " is resolved by " + self.name 42 | } 43 | 44 | func (self *defaultSupport) fail(trouble Trouble) string { 45 | return "trouble:" + strconv.Itoa(trouble.getNumber()) + " cannot be resolved" 46 | } 47 | 48 | type noSupport struct { 49 | *defaultSupport 50 | } 51 | 52 | func (self *noSupport) resolve(trouble Trouble) bool { 53 | return false 54 | } 55 | 56 | func NewNoSupport(name string) *noSupport { 57 | return &noSupport{&defaultSupport{name: name}} 58 | } 59 | 60 | type limitSupport struct { 61 | *defaultSupport 62 | limit int 63 | } 64 | 65 | func (self *limitSupport) resolve(trouble Trouble) bool { 66 | if trouble.getNumber() < self.limit { 67 | return true 68 | } else { 69 | return false 70 | } 71 | } 72 | 73 | func NewLimitSupport(name string, limit int) *limitSupport { 74 | return &limitSupport{&defaultSupport{name: name}, limit} 75 | } 76 | -------------------------------------------------------------------------------- /strategy/strategy.go: -------------------------------------------------------------------------------- 1 | package strategy 2 | 3 | import ( 4 | "math/rand" 5 | ) 6 | 7 | const ( 8 | GUU = iota 9 | CHO 10 | PAA 11 | ) 12 | 13 | var hands []*hand 14 | 15 | func init() { 16 | hands = []*hand{ 17 | &hand{GUU}, 18 | &hand{CHO}, 19 | &hand{PAA}, 20 | } 21 | } 22 | 23 | type hand struct { 24 | handValue int 25 | } 26 | 27 | func getHand(handValue int) *hand { 28 | return hands[handValue] 29 | } 30 | 31 | func (self *hand) IsStrongerThan(h *hand) bool { 32 | return self.fight(h) == 1 33 | } 34 | 35 | func (self *hand) IsWeakerThan(h *hand) bool { 36 | return self.fight(h) == -1 37 | } 38 | 39 | func (self *hand) fight(h *hand) int { 40 | if self == h { 41 | return 0 42 | } else if (self.handValue+1)%3 == h.handValue { 43 | return 1 44 | } else { 45 | return -1 46 | } 47 | } 48 | 49 | // Goでは関数がファーストクラスであるため、戦略がひとつのメソッドのみで 50 | // 完結する場合は、関数を渡すことでStrategyパターンとすることもできる。 51 | // type strategy func() *hand 52 | type strategy interface { 53 | NextHand() *hand 54 | study(win bool) 55 | } 56 | 57 | type winningStrategy struct { 58 | seed int64 59 | won bool 60 | prevHand *hand 61 | } 62 | 63 | func (self *winningStrategy) NextHand() *hand { 64 | if !self.won { 65 | // rand.Seed(self.seed) 66 | self.prevHand = getHand(rand.Intn(3)) 67 | } 68 | return self.prevHand 69 | } 70 | 71 | func (self *winningStrategy) study(win bool) { 72 | self.won = win 73 | } 74 | 75 | type Player struct { 76 | Name string 77 | Strategy strategy 78 | wincount, losecount, gamecount int 79 | } 80 | 81 | func (self *Player) NextHand() *hand { 82 | return self.Strategy.NextHand() 83 | } 84 | 85 | func (self *Player) Win() { 86 | self.wincount++ 87 | self.gamecount++ 88 | } 89 | 90 | func (self *Player) Lose() { 91 | self.losecount++ 92 | self.gamecount++ 93 | } 94 | 95 | func (self *Player) Even() { 96 | self.gamecount++ 97 | } 98 | -------------------------------------------------------------------------------- /abstract_factory/abstract_factory.go: -------------------------------------------------------------------------------- 1 | package abstract_factory 2 | 3 | // 継承ではなくインターフェースによるポリモフィズムを用いる 4 | type item interface { 5 | toString() string 6 | } 7 | 8 | // インターフェースの埋込も可能 9 | type link interface { 10 | item 11 | } 12 | 13 | // インターフェースのポリモフィズムでは構造体間の共通実装やプロパティを 14 | // 利用することができないため、インターフェースを実装した構造体を埋め込む 15 | // ことで実現する 16 | type tray interface { 17 | item 18 | AddToTray(item item) 19 | } 20 | 21 | type baseTray struct { 22 | tray []item 23 | } 24 | 25 | func (self *baseTray) AddToTray(item item) { 26 | self.tray = append(self.tray, item) 27 | } 28 | 29 | type page interface { 30 | AddToContent(item item) 31 | Output() string 32 | } 33 | 34 | type basePage struct { 35 | content []item 36 | } 37 | 38 | func (self *basePage) AddToContent(item item) { 39 | self.content = append(self.content, item) 40 | } 41 | 42 | type factory interface { 43 | CreateLink(caption, url string) link 44 | CreateTray(caption string) tray 45 | CreatePage(title, author string) page 46 | } 47 | 48 | type mdLink struct { 49 | caption, url string 50 | } 51 | 52 | func (self *mdLink) toString() string { 53 | return "[" + self.caption + "](" + self.url + ")" 54 | } 55 | 56 | type mdTray struct { 57 | // 共通処理とプロパティを扱える構造体、かつインターフェースによる 58 | // ポリモフィズムも可能 59 | baseTray 60 | caption string 61 | } 62 | 63 | func (self *mdTray) toString() string { 64 | tray := "- " + self.caption + "\n" 65 | for _, item := range self.tray { 66 | tray += item.toString() + "\n" 67 | } 68 | return tray 69 | } 70 | 71 | type mdPage struct { 72 | basePage 73 | title, author string 74 | } 75 | 76 | func (self *mdPage) Output() string { 77 | content := "title: " + self.title + "\n" 78 | content += "author: " + self.author + "\n" 79 | for _, item := range self.content { 80 | content += item.toString() + "\n" 81 | } 82 | return content 83 | } 84 | 85 | type MdFactory struct { 86 | } 87 | 88 | func (self *MdFactory) CreateLink(caption, url string) link { 89 | return &mdLink{caption, url} 90 | } 91 | func (self *MdFactory) CreateTray(caption string) tray { 92 | return &mdTray{caption: caption} 93 | } 94 | func (self *MdFactory) CreatePage(title, author string) page { 95 | return &mdPage{title: title, author: author} 96 | } 97 | -------------------------------------------------------------------------------- /README_ENGLISH.md: -------------------------------------------------------------------------------- 1 | # Implementation design patterns by golang 2 | 3 | ## Creational patterns 4 | 5 | - [Abstract Factory](https://github.com/monochromegane/go_design_pattern/tree/master/abstract_factory) 6 | - [Builder](https://github.com/monochromegane/go_design_pattern/tree/master/builder) 7 | - [Factory Method](https://github.com/monochromegane/go_design_pattern/tree/master/factory_method) 8 | - [Prototype](https://github.com/monochromegane/go_design_pattern/tree/master/prototype) 9 | - [Singleton](https://github.com/monochromegane/go_design_pattern/tree/master/singleton) 10 | 11 | ## Structural patterns 12 | 13 | - [Adapter](https://github.com/monochromegane/go_design_pattern/tree/master/adapter) 14 | - [Bridge](https://github.com/monochromegane/go_design_pattern/tree/master/bridge) 15 | - [Composite](https://github.com/monochromegane/go_design_pattern/tree/master/composite) 16 | - [Decorator](https://github.com/monochromegane/go_design_pattern/tree/master/decorator) 17 | - [Facade](https://github.com/monochromegane/go_design_pattern/tree/master/facade) 18 | - [Flyweight](https://github.com/monochromegane/go_design_pattern/tree/master/flyweight) 19 | - [Proxy](https://github.com/monochromegane/go_design_pattern/tree/master/proxy) 20 | 21 | ## Behavioral patterns 22 | 23 | - [Chain of Responsibility](https://github.com/monochromegane/go_design_pattern/tree/master/chain_of_responsibility) 24 | - [Command](https://github.com/monochromegane/go_design_pattern/tree/master/command) 25 | - [Interpreter](https://github.com/monochromegane/go_design_pattern/tree/master/interpreter) 26 | - [Iterator](https://github.com/monochromegane/go_design_pattern/tree/master/iterator) 27 | - [Mediator](https://github.com/monochromegane/go_design_pattern/tree/master/mediator) 28 | - [Memento](https://github.com/monochromegane/go_design_pattern/tree/master/memento) 29 | - [Observer](https://github.com/monochromegane/go_design_pattern/tree/master/observer) 30 | - [State](https://github.com/monochromegane/go_design_pattern/tree/master/state) 31 | - [Strategy](https://github.com/monochromegane/go_design_pattern/tree/master/strategy) 32 | - [Template Method](https://github.com/monochromegane/go_design_pattern/tree/master/template_method) 33 | - [Visitor](https://github.com/monochromegane/go_design_pattern/tree/master/visitor) 34 | -------------------------------------------------------------------------------- /README_PORTUGUES.md: -------------------------------------------------------------------------------- 1 | # Implementação de Design Patterns em Go 2 | 3 | ## Padrões de criação 4 | 5 | - [Abstract Factory](https://github.com/monochromegane/go_design_pattern/tree/master/abstract_factory) 6 | - [Builder](https://github.com/monochromegane/go_design_pattern/tree/master/builder) 7 | - [Factory Method](https://github.com/monochromegane/go_design_pattern/tree/master/factory_method) 8 | - [Prototype](https://github.com/monochromegane/go_design_pattern/tree/master/prototype) 9 | - [Singleton](https://github.com/monochromegane/go_design_pattern/tree/master/singleton) 10 | 11 | ## Padrões estruturais 12 | 13 | - [Adapter](https://github.com/monochromegane/go_design_pattern/tree/master/adapter) 14 | - [Bridge](https://github.com/monochromegane/go_design_pattern/tree/master/bridge) 15 | - [Composite](https://github.com/monochromegane/go_design_pattern/tree/master/composite) 16 | - [Decorator](https://github.com/monochromegane/go_design_pattern/tree/master/decorator) 17 | - [Facade](https://github.com/monochromegane/go_design_pattern/tree/master/facade) 18 | - [Flyweight](https://github.com/monochromegane/go_design_pattern/tree/master/flyweight) 19 | - [Proxy](https://github.com/monochromegane/go_design_pattern/tree/master/proxy) 20 | 21 | ## Padrões comportamentais 22 | 23 | - [Chain of Responsibility](https://github.com/monochromegane/go_design_pattern/tree/master/chain_of_responsibility) 24 | - [Command](https://github.com/monochromegane/go_design_pattern/tree/master/command) 25 | - [Interpreter](https://github.com/monochromegane/go_design_pattern/tree/master/interpreter) 26 | - [Iterator](https://github.com/monochromegane/go_design_pattern/tree/master/iterator) 27 | - [Mediator](https://github.com/monochromegane/go_design_pattern/tree/master/mediator) 28 | - [Memento](https://github.com/monochromegane/go_design_pattern/tree/master/memento) 29 | - [Observer](https://github.com/monochromegane/go_design_pattern/tree/master/observer) 30 | - [State](https://github.com/monochromegane/go_design_pattern/tree/master/state) 31 | - [Strategy](https://github.com/monochromegane/go_design_pattern/tree/master/strategy) 32 | - [Template Method](https://github.com/monochromegane/go_design_pattern/tree/master/template_method) 33 | - [Visitor](https://github.com/monochromegane/go_design_pattern/tree/master/visitor) 34 | 35 | 36 | -------------------------------------------------------------------------------- /template_method/template_method.go: -------------------------------------------------------------------------------- 1 | package template_method 2 | 3 | type printer interface { 4 | open() string 5 | print() string 6 | close() string 7 | } 8 | 9 | type AbstractDisplay struct { 10 | } 11 | 12 | // 構造体をレシーバとするメソッドの引数に同じ構造体を渡す必要がある。 13 | // 14 | // なぜか? 15 | // - Go言語の構造体埋込と継承は別物 16 | // - 子構造体を親構造体型の変数に格納することはできない(そもそも親子関係ではなく構造体を内包しているだけ) 17 | // - 親構造体のメソッド内で子構造体を呼び戻すことはしない 18 | // type Abstract struct { some_interface } 19 | // func (self *Abstract) templateMethod() { 20 | // self.method() // panic: runtime error: invalid memory address or nil pointer dereference 21 | // } 22 | // 23 | // どうするか? 24 | // 構造体をレシーバとするメソッドの引数に同じ構造体を渡すパターン(client-specified self pattern)を使う 25 | // これにより親構造体のメソッド内で子構造体の実装を呼ぶことができる 26 | 27 | func (self *AbstractDisplay) Display(printer printer) string { 28 | result := printer.open() 29 | for i := 0; i < 5; i++ { 30 | result += printer.print() 31 | } 32 | result += printer.close() 33 | return result 34 | } 35 | 36 | type CharDisplay struct { 37 | *AbstractDisplay 38 | Char rune 39 | } 40 | 41 | func (self *CharDisplay) open() string { 42 | return "<<" 43 | } 44 | func (self *CharDisplay) print() string { 45 | return string(self.Char) 46 | } 47 | func (self *CharDisplay) close() string { 48 | return ">>" 49 | } 50 | 51 | type StringDisplay struct { 52 | *AbstractDisplay 53 | Str string 54 | } 55 | 56 | func (self *StringDisplay) open() string { 57 | return self.printLine() 58 | } 59 | func (self *StringDisplay) print() string { 60 | return "| " + self.Str + " |\n" 61 | } 62 | func (self *StringDisplay) close() string { 63 | return self.printLine() 64 | } 65 | 66 | func (self *StringDisplay) printLine() string { 67 | line := "+-" 68 | for _, _ = range self.Str { 69 | line += "-" 70 | } 71 | line += "-+\n" 72 | return line 73 | } 74 | 75 | // 継承を利用しないTemplateMethodパターン 76 | 77 | // Goでは継承を利用したパターンは実装がいびつになるのでオススメしない。 78 | // 例えばテンプレートメソッドをもつ構造体とメソッドを持つインターフェースを 79 | // 分けて定義して処理を移譲する構成にすればスッキリする 80 | // が、これは継承を使っていないのでTemplateMethodパターンというよりは 81 | // Strategyパターンに近い 82 | 83 | // type Display struct { 84 | // printer printer 85 | // } 86 | // 87 | // func (self *Display) Display() string { 88 | // result := self.printer.open() 89 | // for i := 0; i < 5; i++ { 90 | // result += self.printer.print() 91 | // } 92 | // result += self.printer.close() 93 | // return result 94 | // } 95 | -------------------------------------------------------------------------------- /visitor/visitor.go: -------------------------------------------------------------------------------- 1 | package visitor 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | type visitor interface { 8 | visitFile(file *file) string 9 | visitDir(directory *directory) string 10 | } 11 | 12 | type element interface { 13 | Accept(visitor visitor) string 14 | } 15 | 16 | type entry interface { 17 | element 18 | getName() string 19 | getSize() int 20 | Add(entry entry) 21 | } 22 | 23 | type defaultEntry struct { 24 | entry 25 | name string 26 | } 27 | 28 | func (self *defaultEntry) getName() string { 29 | return self.name 30 | } 31 | 32 | func (self *defaultEntry) print(entry entry) string { 33 | return entry.getName() + " (" + strconv.Itoa(entry.getSize()) + ")\n" 34 | } 35 | 36 | type file struct { 37 | *defaultEntry 38 | size int 39 | } 40 | 41 | func (self *file) getSize() int { 42 | return self.size 43 | } 44 | 45 | func (self *file) Add(entry entry) {} 46 | 47 | func (self *file) Accept(visitor visitor) string { 48 | return visitor.visitFile(self) 49 | } 50 | 51 | type directory struct { 52 | *defaultEntry 53 | dir []entry 54 | } 55 | 56 | func (self *directory) getSize() int { 57 | size := 0 58 | for _, dir := range self.dir { 59 | size += dir.getSize() 60 | } 61 | return size 62 | } 63 | 64 | func (self *directory) Add(entry entry) { 65 | self.dir = append(self.dir, entry) 66 | } 67 | 68 | func (self *directory) Accept(visitor visitor) string { 69 | return visitor.visitDir(self) 70 | } 71 | 72 | type listVisitor struct { 73 | currentDir string 74 | } 75 | 76 | func (self *listVisitor) visitFile(file *file) string { 77 | return self.currentDir + "/" + file.print(file) 78 | } 79 | 80 | func (self *listVisitor) visitDir(directory *directory) string { 81 | saveDir := self.currentDir 82 | list := self.currentDir + "/" + directory.print(directory) 83 | self.currentDir += "/" + directory.getName() 84 | for _, dir := range directory.dir { 85 | list += dir.Accept(self) 86 | } 87 | self.currentDir = saveDir 88 | return list 89 | } 90 | 91 | // 利用側に埋込構造体を意識させないためのインスタンス生成関数。 92 | func NewFile(name string, size int) *file { 93 | return &file{ 94 | defaultEntry: &defaultEntry{name: name}, // 埋込時のキーには構造体と同名のものを使うことができる 95 | size: size, 96 | } 97 | } 98 | func NewDirectory(name string) *directory { 99 | return &directory{defaultEntry: &defaultEntry{name: name}} 100 | } 101 | -------------------------------------------------------------------------------- /interpreter/interpreter.go: -------------------------------------------------------------------------------- 1 | package interpreter 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | type node interface { 8 | Parse(context *context) 9 | ToString() string 10 | } 11 | 12 | type ProgramNode struct { 13 | commandListNode node 14 | } 15 | 16 | func (self *ProgramNode) Parse(context *context) { 17 | context.skipToken("program") 18 | self.commandListNode = &commandListNode{} 19 | self.commandListNode.Parse(context) 20 | } 21 | 22 | func (self *ProgramNode) ToString() string { 23 | return "program: " + self.commandListNode.ToString() 24 | } 25 | 26 | type commandListNode struct { 27 | list []node 28 | } 29 | 30 | func (self *commandListNode) Parse(context *context) { 31 | for { 32 | if context.currentToken == "end" { 33 | break 34 | } else { 35 | commandNode := &commandNode{} 36 | commandNode.Parse(context) 37 | self.list = append(self.list, commandNode) 38 | } 39 | } 40 | } 41 | 42 | func (self *commandListNode) ToString() string { 43 | var str string 44 | for _, l := range self.list { 45 | str += l.ToString() 46 | } 47 | return str 48 | } 49 | 50 | type commandNode struct { 51 | node node 52 | } 53 | 54 | func (self *commandNode) Parse(context *context) { 55 | self.node = &primitiveCommandNode{} 56 | self.node.Parse(context) 57 | } 58 | 59 | func (self *commandNode) ToString() string { 60 | return self.node.ToString() 61 | } 62 | 63 | type primitiveCommandNode struct { 64 | name string 65 | } 66 | 67 | func (self *primitiveCommandNode) Parse(context *context) { 68 | self.name = context.currentToken 69 | context.skipToken(self.name) 70 | } 71 | 72 | func (self *primitiveCommandNode) ToString() string { 73 | return self.name + " " 74 | } 75 | 76 | type context struct { 77 | text string 78 | tokens []string 79 | currentToken string 80 | } 81 | 82 | func NewContext(text string) *context { 83 | context := &context{ 84 | text: text, 85 | tokens: strings.Fields(text), 86 | } 87 | context.nextToken() 88 | return context 89 | } 90 | 91 | func (self *context) nextToken() string { 92 | if len(self.tokens) == 0 { 93 | self.currentToken = "" 94 | } else { 95 | self.currentToken = self.tokens[0] 96 | self.tokens = self.tokens[1:] 97 | } 98 | return self.currentToken 99 | } 100 | 101 | func (self *context) skipToken(token string) { 102 | self.nextToken() 103 | } 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go言語でのデザインパターン実装 2 | 3 | このリポジトリはGo言語でのデザインパターン実装を試したものです。 4 | ここで得られた構造体実装に関する知見は[ブログ](http://blog.monochromegane.com/)に`Go言語による構造体実装パターン`としてまとめています。 5 | 6 | パターン実装にあたっては、結城 浩さんの[増補改訂版Java言語で学ぶデザインパターン入門](http://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%89%88Java%E8%A8%80%E8%AA%9E%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E5%85%A5%E9%96%80-%E7%B5%90%E5%9F%8E-%E6%B5%A9/dp/4797327030/ref=sr_1_2?ie=UTF8&qid=1395468803&sr=8-2&keywords=%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)を参考にしました。 7 | 各デザインパターンの解説についてはそちらを参考にしてください。 8 | 9 | # デザインパターン 10 | 11 | ## 生成に関するパターン 12 | 13 | - [Abstract Factory](https://github.com/monochromegane/go_design_pattern/tree/master/abstract_factory) 14 | - [Builder](https://github.com/monochromegane/go_design_pattern/tree/master/builder) 15 | - [Factory Method](https://github.com/monochromegane/go_design_pattern/tree/master/factory_method) 16 | - [Prototype](https://github.com/monochromegane/go_design_pattern/tree/master/prototype) 17 | - [Singleton](https://github.com/monochromegane/go_design_pattern/tree/master/singleton) 18 | 19 | ## 構造に関するパターン 20 | 21 | - [Adapter](https://github.com/monochromegane/go_design_pattern/tree/master/adapter) 22 | - [Bridge](https://github.com/monochromegane/go_design_pattern/tree/master/bridge) 23 | - [Composite](https://github.com/monochromegane/go_design_pattern/tree/master/composite) 24 | - [Decorator](https://github.com/monochromegane/go_design_pattern/tree/master/decorator) 25 | - [Facade](https://github.com/monochromegane/go_design_pattern/tree/master/facade) 26 | - [Flyweight](https://github.com/monochromegane/go_design_pattern/tree/master/flyweight) 27 | - [Proxy](https://github.com/monochromegane/go_design_pattern/tree/master/proxy) 28 | 29 | ## 振る舞いに関するパターン 30 | 31 | - [Chain of Responsibility](https://github.com/monochromegane/go_design_pattern/tree/master/chain_of_responsibility) 32 | - [Command](https://github.com/monochromegane/go_design_pattern/tree/master/command) 33 | - [Interpreter](https://github.com/monochromegane/go_design_pattern/tree/master/interpreter) 34 | - [Iterator](https://github.com/monochromegane/go_design_pattern/tree/master/iterator) 35 | - [Mediator](https://github.com/monochromegane/go_design_pattern/tree/master/mediator) 36 | - [Memento](https://github.com/monochromegane/go_design_pattern/tree/master/memento) 37 | - [Observer](https://github.com/monochromegane/go_design_pattern/tree/master/observer) 38 | - [State](https://github.com/monochromegane/go_design_pattern/tree/master/state) 39 | - [Strategy](https://github.com/monochromegane/go_design_pattern/tree/master/strategy) 40 | - [Template Method](https://github.com/monochromegane/go_design_pattern/tree/master/template_method) 41 | - [Visitor](https://github.com/monochromegane/go_design_pattern/tree/master/visitor) 42 | 43 | --------------------------------------------------------------------------------