From 450074a3d6dff46017a98e7fa8ff16fd18c6fccb Mon Sep 17 00:00:00 2001 From: nynicg Date: Wed, 1 May 2019 21:22:34 +0800 Subject: [PATCH 01/19] template pattern --- behavioral/strategy/main.go | 36 +++++++++++++ behavioral/template/main.go | 102 ++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 behavioral/strategy/main.go create mode 100644 behavioral/template/main.go diff --git a/behavioral/strategy/main.go b/behavioral/strategy/main.go new file mode 100644 index 0000000..84017ca --- /dev/null +++ b/behavioral/strategy/main.go @@ -0,0 +1,36 @@ +package main + +type Operator interface { + Apply(int, int) int +} + +// 通过定义内部的Operator实现不同策略的切换 +type Operation struct { + Operator Operator +} + +func (o *Operation) Operate(leftValue, rightValue int) int { + return o.Operator.Apply(leftValue, rightValue) +} + +type Addition struct{} + +func (Addition) Apply(lval, rval int) int { + return lval + rval +} + +type Multiplication struct{} + +func (Multiplication) Apply(lval, rval int) int { + return lval * rval +} + +func main(){ + a ,b := 2 ,4 + op := &Operation{ + Addition{}, + } + println(op.Operate(a ,b))// 6 + op.Operator = Multiplication{} + println(op.Operate(a ,b))// 8 +} diff --git a/behavioral/template/main.go b/behavioral/template/main.go new file mode 100644 index 0000000..f1c5245 --- /dev/null +++ b/behavioral/template/main.go @@ -0,0 +1,102 @@ +// 存疑的部分. +// 模板模式和策略模式在很多时候给人感觉基本可以划等号,事实上两者侧重的方向不同. +// 策略模式倾向于通过改变结构的属性从而改变算法,模板模式则倾向于事先定义一个处理的流程,该流程是可以被整体替换的. +// 个人认为应该保证模板模式下的结构体应当独立出来,每个流程单独被调用. +// 感觉以下两种写法都有点别扭,待指正 + +package main + +type Game interface { + OnStart() + OnEnd() +} + +type GameRunner struct {} + +func (GameRunner)Go(g Game){ + g.OnStart() + g.OnEnd() +} + +type FPSGame struct {} + +func (f FPSGame)OnStart(){ + println("fps game start") +} + +func (f FPSGame)OnEnd(){ + println("fps game end") +} + +type RPGGame struct {} + +func (RPGGame) OnStart() { + println("rpg game start") +} + +func (RPGGame) OnEnd() { + println("rpg game end") +} + +func main(){ + tpl := GameRunner{} + tpl.Go(FPSGame{}) + tpl.Go(RPGGame{}) + // output: + /* + fps game start + fps game end + rpg game start + rpg game end + */ +} + + +// ______________________________Another_______________ + +//type Game struct { +// OnStart func() +// OnEnd func() +//} +// +//func (g Game)Go(){ +// g.OnStart() +// g.OnEnd() +//} +// +//type FPSGame struct {Game} +// +//func NewFPSGame()FPSGame{ +// g := Game{ +// OnStart: func() { +// fmt.Println("start fps") +// time.Sleep(time.Second / 2) +// }, +// OnEnd: func() { +// fmt.Println("you are killed") +// }, +// } +// return FPSGame{g} +//} +// +//type RPGGame struct {Game} +// +//func NewRPGGame()RPGGame{ +// g := Game{ +// OnStart: func() { +// fmt.Println("start rpg") +// time.Sleep(time.Second / 2) +// }, +// OnEnd: func() { +// fmt.Println("you win") +// }, +// } +// return RPGGame{g} +//} +// +//func main(){ +// NewFPSGame().Go() +// println() +// NewRPGGame().Go() +//} + From 821af9d44bc75f227dd21f87a089f6951a062599 Mon Sep 17 00:00:00 2001 From: nynicg Date: Thu, 2 May 2019 08:00:01 +0800 Subject: [PATCH 02/19] chain of responsibility --- behavioral/chain_of_responsibility/go_test.go | 42 +++++++++++ behavioral/chain_of_responsibility/main.go | 74 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 behavioral/chain_of_responsibility/go_test.go create mode 100644 behavioral/chain_of_responsibility/main.go diff --git a/behavioral/chain_of_responsibility/go_test.go b/behavioral/chain_of_responsibility/go_test.go new file mode 100644 index 0000000..536288c --- /dev/null +++ b/behavioral/chain_of_responsibility/go_test.go @@ -0,0 +1,42 @@ +package main + +import ( + "log" + "sync" + "testing" + "time" +) + +// 想弄清楚slice遍历时被修改到底会发生什么. +// 结果是安全失败. +// 并不意味着是线程安全的. +func TestGo(t *testing.T){ + s := make([]int ,0) + wg := &sync.WaitGroup{} + wg.Add(2) + for i:=0 ;i<10 ;i++{ + s = append(s, i) + } + + itv := time.Second + go func() { + defer wg.Done() + for k ,v := range s{ + println(k ,v) + time.Sleep(itv) + } + }() + + time.Sleep(itv) + + go func() { + defer wg.Done() + s = append(s ,810) + time.Sleep(itv) + s = append(s ,114) + log.Println("add") + }() + + wg.Wait() + log.Println(s) +} diff --git a/behavioral/chain_of_responsibility/main.go b/behavioral/chain_of_responsibility/main.go new file mode 100644 index 0000000..e88bc9a --- /dev/null +++ b/behavioral/chain_of_responsibility/main.go @@ -0,0 +1,74 @@ +package main + +type GameType int + +const ( + TypeFPS GameType = 1 + TypeRPG = TypeFPS << 1 +) + +type Game interface { + Type() GameType + Start(player string) +} + +// chain of responsibility +type GameSelector struct { + GameList []Game +} + +func (g *GameSelector)AddGame(games ...Game){ + g.GameList = append(g.GameList ,games...) +} + +func (g GameSelector) Start(t GameType, player string) { + for _ ,v := range g.GameList{ + if v.Type() == t{ + v.Start(player) + return + } + } +} + +type FPSGame struct { + t GameType +} + +func (f FPSGame) Start(player string) { + println(player ,"join in fps game") +} + +func (f FPSGame)Type() GameType{ + return f.t +} + +type RPGGame struct { + t GameType +} + +func (RPGGame) Start(player string) { + println(player ,"join in rpg game") +} + +func (r RPGGame)Type() GameType{ + return r.t +} + +func main(){ + fps := FPSGame{TypeFPS} + rpg := RPGGame{TypeRPG} + + sl := GameSelector{make([]Game ,0)} + sl.AddGame(fps ,rpg) + + player := "icg" + sl.Start(TypeRPG ,player) + println() + sl.Start(TypeFPS ,player) + // output: + /* + icg join in rpg game + + icg join in fps game + */ +} From 48ed8bc09466888fbb321269e488cfa18a79bee1 Mon Sep 17 00:00:00 2001 From: nynicg Date: Thu, 2 May 2019 09:37:29 +0800 Subject: [PATCH 03/19] command pattern --- README.md | 2 +- behavioral/chain_of_responsibility/main.go | 2 +- behavioral/command/main.go | 80 ++++++++++++++++++++++ behavioral/template/main.go | 1 - 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 behavioral/command/main.go diff --git a/README.md b/README.md index 7d9f5f7..1f8bb61 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ A curated collection of idiomatic design & application patterns for Go language. | Pattern | Description | Status | |:-------:|:----------- |:------:| -| [Chain of Responsibility](/behavioral/chain_of_responsibility.md) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✘ | +| [Chain of Responsibility](/behavioral/chain_of_responsibility.md) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✔ | | [Command](/behavioral/command.md) | Bundles a command and arguments to call later | ✘ | | [Mediator](/behavioral/mediator.md) | Connects objects and acts as a proxy | ✘ | | [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ | diff --git a/behavioral/chain_of_responsibility/main.go b/behavioral/chain_of_responsibility/main.go index e88bc9a..a8b0b7e 100644 --- a/behavioral/chain_of_responsibility/main.go +++ b/behavioral/chain_of_responsibility/main.go @@ -58,7 +58,7 @@ func main(){ fps := FPSGame{TypeFPS} rpg := RPGGame{TypeRPG} - sl := GameSelector{make([]Game ,0)} + sl := GameSelector{} sl.AddGame(fps ,rpg) player := "icg" diff --git a/behavioral/command/main.go b/behavioral/command/main.go new file mode 100644 index 0000000..b6d89e5 --- /dev/null +++ b/behavioral/command/main.go @@ -0,0 +1,80 @@ +// 主要分为四个部分,command ,ConcreteCommand ,receiver ,invoker. +// 分别对应以下GameCommand ,(CommandAttack|CommandEscape) ,GamePlayer ,Invoker. +package main + +// command +type GameCommand interface { + Execute() +} + +// ConcreteCommand +type CommandAttack struct {Player GamePlayer} + +func (c CommandAttack)Execute(){ + c.Player.Attack() +} + +// ConcreteCommand +type CommandEscape struct {Player GamePlayer} + +func (c CommandEscape)Execute(){ + c.Player.Escape() +} + +// receiver +type GamePlayer interface { + Attack() + Escape() +} + +type GunPlayer struct {Name string} + +func (g GunPlayer) Attack() { + println(g.Name ,"opened fire") +} + +func (g GunPlayer) Escape() { + println(g.Name ,"escape") +} + +// invoker +type CommandInvoker struct { + CommandList chan GameCommand +} + +func (in *CommandInvoker)CallCommands(){ + for{ + select { + case cmd := <- in.CommandList: + cmd.Execute() + default: + return + } + } +} + +func (in *CommandInvoker)PushCommands(c ...GameCommand){ + for _ ,v := range c{ + in.CommandList <- v + } +} + +func main(){ + invoker := &CommandInvoker{ + make(chan GameCommand ,10), + } + + playerA := GunPlayer{"icg"} + attk := CommandAttack{playerA} + escp := CommandEscape{playerA} + + invoker.PushCommands(attk ,escp ,escp ,attk) + invoker.CallCommands() + // output: + /* + icg opened fire + icg escape + icg escape + icg opened fire + */ +} diff --git a/behavioral/template/main.go b/behavioral/template/main.go index f1c5245..d6aaa18 100644 --- a/behavioral/template/main.go +++ b/behavioral/template/main.go @@ -3,7 +3,6 @@ // 策略模式倾向于通过改变结构的属性从而改变算法,模板模式则倾向于事先定义一个处理的流程,该流程是可以被整体替换的. // 个人认为应该保证模板模式下的结构体应当独立出来,每个流程单独被调用. // 感觉以下两种写法都有点别扭,待指正 - package main type Game interface { From 1d32ce54f044838da6938c34d4c1d207d61fff33 Mon Sep 17 00:00:00 2001 From: nynicg Date: Thu, 2 May 2019 09:38:16 +0800 Subject: [PATCH 04/19] command pattern --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f8bb61..f6a8f06 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ A curated collection of idiomatic design & application patterns for Go language. | Pattern | Description | Status | |:-------:|:----------- |:------:| | [Chain of Responsibility](/behavioral/chain_of_responsibility.md) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✔ | -| [Command](/behavioral/command.md) | Bundles a command and arguments to call later | ✘ | +| [Command](/behavioral/command.md) | Bundles a command and arguments to call later | ✔ | | [Mediator](/behavioral/mediator.md) | Connects objects and acts as a proxy | ✘ | | [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ | | [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ | From 644fd81d3e08131617d3a0af4c68c527d316f50a Mon Sep 17 00:00:00 2001 From: nynicg Date: Thu, 2 May 2019 09:40:20 +0800 Subject: [PATCH 05/19] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f6a8f06..1d4b001 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,8 @@ A curated collection of idiomatic design & application patterns for Go language. | Pattern | Description | Status | |:-------:|:----------- |:------:| -| [Chain of Responsibility](/behavioral/chain_of_responsibility.md) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✔ | -| [Command](/behavioral/command.md) | Bundles a command and arguments to call later | ✔ | +| [Chain of Responsibility](/behavioral/chain_of_responsibility/main.go) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✔ | +| [Command](/behavioral/command/main.go) | Bundles a command and arguments to call later | ✔ | | [Mediator](/behavioral/mediator.md) | Connects objects and acts as a proxy | ✘ | | [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ | | [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ | From af1573a1d9dc0d248fccd018b40bb32be42eb048 Mon Sep 17 00:00:00 2001 From: nynicg Date: Thu, 2 May 2019 09:52:04 +0800 Subject: [PATCH 06/19] command pattern --- behavioral/command/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/behavioral/command/main.go b/behavioral/command/main.go index b6d89e5..b32fe61 100644 --- a/behavioral/command/main.go +++ b/behavioral/command/main.go @@ -1,3 +1,4 @@ +// 命令模式(command pattern)主要解耦了行为和接收者,使之可以任意组合为一个完整的命令,并在合适的时候被调用 // 主要分为四个部分,command ,ConcreteCommand ,receiver ,invoker. // 分别对应以下GameCommand ,(CommandAttack|CommandEscape) ,GamePlayer ,Invoker. package main From 66ce5358a450c660439c15c08f882941dee5b2f3 Mon Sep 17 00:00:00 2001 From: nynicg Date: Thu, 2 May 2019 12:22:10 +0800 Subject: [PATCH 07/19] mediator pattern --- README.md | 2 +- behavioral/mediator/main.go | 76 +++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 behavioral/mediator/main.go diff --git a/README.md b/README.md index 1d4b001..56a6c98 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ A curated collection of idiomatic design & application patterns for Go language. |:-------:|:----------- |:------:| | [Chain of Responsibility](/behavioral/chain_of_responsibility/main.go) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✔ | | [Command](/behavioral/command/main.go) | Bundles a command and arguments to call later | ✔ | -| [Mediator](/behavioral/mediator.md) | Connects objects and acts as a proxy | ✘ | +| [Mediator](/behavioral/mediator/main.go) | Connects objects and acts as a proxy | ✔ | | [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ | | [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ | | [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ | diff --git a/behavioral/mediator/main.go b/behavioral/mediator/main.go new file mode 100644 index 0000000..90d0d5c --- /dev/null +++ b/behavioral/mediator/main.go @@ -0,0 +1,76 @@ +// 中介者模式(mediator pattern) +// 当两个对象存在复杂的依赖关系时,考虑增加一个中介者使之解耦,使他们不需要进行显示的引用. +// 但问题在于中介本身会去实现复杂的逻辑,进而导致中介者变得复杂臃肿难以维护. +// +// 这里是竞价和消息交换的例子. +// 参与竞价的玩家只需要向中介出价就可以知道是否能买到商品,由中介确定谁的出价高 +package main + +import ( + "log" + "math/rand" + "time" +) + +// buyer 之间通过中介进行引用 +type Buyer struct { + m *Mediator + Name string// unique +} + +func (b Buyer)Bid(price int){ + if p ,ok := b.m.isMaxPrice(b ,price);ok{ + log.Println(b.Name ,"are in lead temporarily with" ,p) + }else{ + log.Println(b.Name ,"lose with" ,p) + } +} + +type Mediator struct { + Buyers map[Buyer]int + MaxPrice int + MaxPriceBuyer Buyer +} + +func (m *Mediator)isMaxPrice(b Buyer ,price int)(int ,bool){ + if b.Name == m.MaxPriceBuyer.Name{ + return m.MaxPrice ,true + } + m.Buyers[b] = price + for k ,v := range m.Buyers{ + if v > m.MaxPrice{ + m.MaxPrice = v + m.MaxPriceBuyer = k + } + } + if b.Name == m.MaxPriceBuyer.Name{ + return price ,true + } + return price ,false +} + +func main(){ + m := &Mediator{ + make(map[Buyer]int), + 0, + Buyer{}, + } + + icg := Buyer{m ,"icg"} + nyn := Buyer{m ,"nyn"} + + rand.Seed(time.Now().UnixNano()) + for i:=0 ;i<3 ;i++{ + icg.Bid(rand.Intn(10000)) + nyn.Bid(rand.Intn(10000)) + } + // output: + /* + 2019/05/02 12:19:52 icg are in lead temporarily with 1024 + 2019/05/02 12:19:52 nyn are in lead temporarily with 4232 + 2019/05/02 12:19:52 icg are in lead temporarily with 6412 + 2019/05/02 12:19:52 nyn are in lead temporarily with 6747 + 2019/05/02 12:19:52 icg lose with 4951 + 2019/05/02 12:19:52 nyn are in lead temporarily with 6747 + */ +} From da2587d3f2fc0331e8f55ba0f888367f3a8e08f3 Mon Sep 17 00:00:00 2001 From: nynicg Date: Thu, 2 May 2019 18:16:11 +0800 Subject: [PATCH 08/19] memento pattern --- README.md | 2 +- behavioral/mediator/main.go | 4 +- behavioral/memento/main.go | 78 +++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 behavioral/memento/main.go diff --git a/README.md b/README.md index 56a6c98..e96ca76 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ A curated collection of idiomatic design & application patterns for Go language. | [Chain of Responsibility](/behavioral/chain_of_responsibility/main.go) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✔ | | [Command](/behavioral/command/main.go) | Bundles a command and arguments to call later | ✔ | | [Mediator](/behavioral/mediator/main.go) | Connects objects and acts as a proxy | ✔ | -| [Memento](/behavioral/memento.md) | Generate an opaque token that can be used to go back to a previous state | ✘ | +| [Memento](/behavioral/memento/main.go) | Generate an opaque token that can be used to go back to a previous state | ✔ | | [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ | | [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ | | [State](/behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state | ✘ | diff --git a/behavioral/mediator/main.go b/behavioral/mediator/main.go index 90d0d5c..ac20b50 100644 --- a/behavioral/mediator/main.go +++ b/behavioral/mediator/main.go @@ -1,8 +1,8 @@ // 中介者模式(mediator pattern) -// 当两个对象存在复杂的依赖关系时,考虑增加一个中介者使之解耦,使他们不需要进行显示的引用. +// 当两个对象存在复杂的依赖关系时,考虑增加一个中介者使之解耦,使他们不需要进行显式的引用. // 但问题在于中介本身会去实现复杂的逻辑,进而导致中介者变得复杂臃肿难以维护. // -// 这里是竞价和消息交换的例子. +// 这里是竞价的例子. // 参与竞价的玩家只需要向中介出价就可以知道是否能买到商品,由中介确定谁的出价高 package main diff --git a/behavioral/memento/main.go b/behavioral/memento/main.go new file mode 100644 index 0000000..5e6428a --- /dev/null +++ b/behavioral/memento/main.go @@ -0,0 +1,78 @@ +// 备忘录模式 memento pattern +// 在不影响原结构封装的情况下,能够暂时保存一个结构的状态,并能够恢复 +// 这里是一个游戏存档的例子,尝试保存玩家当前位置,并在读档的时候恢复 +package main + +import ( + "container/list" + "log" +) + +type Player struct { + X,Y int + Name string + // other info +} + +func (p *Player)MoveTo(x,y int){ + p.X = x + p.Y = y +} + +func (p Player)Save()PlayerMemento{ + return PlayerMemento{ + X:p.X, + Y:p.Y, + } +} + +func (p *Player)Restore(m PlayerMemento){ + p.X = m.X + p.Y = m.Y +} + +type PlayerMemento struct { + X,Y int +} + +type PlayerCareTaker struct { + MementoList *list.List +} + +func (ct *PlayerCareTaker)AddMemento(memento PlayerMemento){ + ct.MementoList.PushFront(memento) +} + +func (ct *PlayerCareTaker)RemoveLast()PlayerMemento{ + ele := ct.MementoList.Front() + val := ct.MementoList.Remove(ele) + if memento ,ok := val.(PlayerMemento);ok{ + return memento + }else{ + return PlayerMemento{} + } +} + +func main(){ + ct := &PlayerCareTaker{list.New()} + icg := &Player{ + X:114, + Y:514, + Name:"icg", + } + ct.AddMemento(icg.Save()) + log.Println(icg.X ,icg.Y) + + icg.MoveTo(810 ,19) + log.Println(icg.X ,icg.Y) + ct.AddMemento(icg.Save()) + + icg.MoveTo(0 ,0) + log.Println(icg.X ,icg.Y) + + icg.Restore(ct.RemoveLast()) + log.Println(icg.X ,icg.Y) + + icg.Restore(ct.RemoveLast()) + log.Println(icg.X ,icg.Y) +} From ab8d8e908fbf84699931da09d04a62e7a06527e8 Mon Sep 17 00:00:00 2001 From: nynicg Date: Fri, 3 May 2019 10:48:46 +0800 Subject: [PATCH 09/19] state pattern --- README.md | 4 +- behavioral/command/main.go | 11 ++-- behavioral/memento/main.go | 16 ++++- behavioral/state/main.go | 84 +++++++++++++++++++++++++ behavioral/state/problem.go | 118 ++++++++++++++++++++++++++++++++++++ 5 files changed, 225 insertions(+), 8 deletions(-) create mode 100644 behavioral/state/main.go create mode 100644 behavioral/state/problem.go diff --git a/README.md b/README.md index e96ca76..6b76f10 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,9 @@ A curated collection of idiomatic design & application patterns for Go language. | [Memento](/behavioral/memento/main.go) | Generate an opaque token that can be used to go back to a previous state | ✔ | | [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ | | [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ | -| [State](/behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state | ✘ | +| [State](/behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state | ✔ | | [Strategy](/behavioral/strategy.md) | Enables an algorithm's behavior to be selected at runtime | ✔ | -| [Template](/behavioral/template.md) | Defines a skeleton class which defers some methods to subclasses | ✘ | +| [Template](/behavioral/template.md) | Defines a skeleton class which defers some methods to subclasses | ✔ | | [Visitor](/behavioral/visitor.md) | Separates an algorithm from an object on which it operates | ✘ | ## Synchronization Patterns diff --git a/behavioral/command/main.go b/behavioral/command/main.go index b32fe61..6747dd5 100644 --- a/behavioral/command/main.go +++ b/behavioral/command/main.go @@ -69,13 +69,14 @@ func main(){ attk := CommandAttack{playerA} escp := CommandEscape{playerA} - invoker.PushCommands(attk ,escp ,escp ,attk) + invoker.PushCommands(attk ,escp ,escp ,attk ,escp) invoker.CallCommands() // output: /* - icg opened fire - icg escape - icg escape - icg opened fire + icg opened fire + icg escape + icg escape + icg opened fire + icg escape */ } diff --git a/behavioral/memento/main.go b/behavioral/memento/main.go index 5e6428a..047e635 100644 --- a/behavioral/memento/main.go +++ b/behavioral/memento/main.go @@ -8,10 +8,14 @@ import ( "log" ) +// originator type Player struct { + // 需要记录的数据可以考虑单独封装 + // type Pos struct{X,Y int} X,Y int - Name string + // other info + Name string } func (p *Player)MoveTo(x,y int){ @@ -31,10 +35,12 @@ func (p *Player)Restore(m PlayerMemento){ p.Y = m.Y } +// memento type PlayerMemento struct { X,Y int } +// caretaker type PlayerCareTaker struct { MementoList *list.List } @@ -75,4 +81,12 @@ func main(){ icg.Restore(ct.RemoveLast()) log.Println(icg.X ,icg.Y) + /* + output: + 2019/05/02 18:18:03 114 514 + 2019/05/02 18:18:03 810 19 + 2019/05/02 18:18:03 0 0 + 2019/05/02 18:18:03 810 19 + 2019/05/02 18:18:03 114 514 + */ } diff --git a/behavioral/state/main.go b/behavioral/state/main.go new file mode 100644 index 0000000..b586d18 --- /dev/null +++ b/behavioral/state/main.go @@ -0,0 +1,84 @@ +// 状态模式 state pattern. +// 与策略模式在一些场景可以通用,但策略模式倾向于调用者根据情况手动改变内部策略以切换算法, +// 状态模式倾向于由Context内部自行管理状态,只需要设定初始状态即可,不需要手动切换. +// +// 以下是以跷跷板seesaw为例,分为[左侧高LeftState|右侧高RightState] +package main + +import ( + "math/rand" + "time" +) + +// state +type SeesawState interface { + LiftLeftSide(S *Seesaw) + LiftRightSide(S *Seesaw) +} + +type LeftState struct {} + +func (LeftState) LiftLeftSide(S *Seesaw) { + println("↑LEFT > left side wads already lifted") +} + +func (l LeftState) LiftRightSide(S *Seesaw) { + println("RIGHT↑ > lift right side") + S.State = RightState{} +} + +type RightState struct {} + +func (r RightState) LiftLeftSide(S *Seesaw) { + println("↑LEFT > lift left side") + S.State = LeftState{} +} + +func (RightState) LiftRightSide(S *Seesaw) { + println("RIGHT↑ > right side wads already lifted") +} + +// context +type Seesaw struct { + State SeesawState +} + +func (s *Seesaw)MakeLeftUp(){ + s.State.LiftLeftSide(s) +} + +func (s *Seesaw)MakeRightUp(){ + s.State.LiftRightSide(s) +} + +func main(){ + // init left + seesaw := &Seesaw{ + State:LeftState{}, + } + + rand.Seed(time.Now().UnixNano()) + for i:=0 ;i<10 ;i++{ + if rand.Intn(2) == 1{ + // ▄▃▂ + seesaw.MakeLeftUp() + }else{ + // ▂▃▄ + seesaw.MakeRightUp() + } + } + /* + output: + RIGHT↑ > lift right side + RIGHT↑ > right side wads already lifted + RIGHT↑ > right side wads already lifted + ↑LEFT > lift left side + ↑LEFT > left side wads already lifted + ↑LEFT > left side wads already lifted + ↑LEFT > left side wads already lifted + RIGHT↑ > lift right side + RIGHT↑ > right side wads already lifted + ↑LEFT > lift left side + */ +} + diff --git a/behavioral/state/problem.go b/behavioral/state/problem.go new file mode 100644 index 0000000..159c2d6 --- /dev/null +++ b/behavioral/state/problem.go @@ -0,0 +1,118 @@ +// 存疑部分. +// +// 这里是以玩家的健康状态为基准,影响生命回复和受到伤害的例子,有三个状态[健康HealthyState|受伤WoundedState|死亡DeadState]. +// 和main.go中的跷跷板例子由行为驱动状态变化不同.以下例子的行为是受到数据影响的,结果就是达不到完全消除if-else的效果 +// +// 疑问: +// 1. 很多地方说状态模式可以消除if-else,事实上要做到自行的状态切换很多时候还是会用到if-else,这里的消除应当是指 +// 将巨大的条件语句拆分开(?) +// 2. 还是说这种由数据决定状态的事务逻辑下不适合使用状态模式 +package main + +import ( + "errors" + "fmt" +) + +// state +type PlayerState interface { + Heal(p *Player) error + Hurt(p *Player ,dmg int) +} + +type HealthyState struct {} + +func (h HealthyState)Heal(p *Player) error{ + return nil +} + +func (h HealthyState)Hurt(p *Player ,dmg int){ + if dmg > 0 && dmg < p.MaxHealth{ + p.Health = p.Health - dmg + p.State = WoundedState{} + }else if dmg > p.MaxHealth{ + p.Health = 0 + p.State = DeadState{} + } +} + +type WoundedState struct {} + +func (WoundedState)Heal(p *Player) error{ + if p.Health >= p.MaxHealth - 5{ + fmt.Printf("healing from %d to %d\n" ,p.Health ,p.MaxHealth) + p.State = HealthyState{} + p.Health = p.MaxHealth + }else{ + fmt.Printf("healing from %d to %d\n" ,p.Health ,p.Health+5) + p.Health = p.Health + 5 + } + return nil +} + +func (h WoundedState)Hurt(p *Player ,dmg int){ + if p.Health > dmg{ + p.Health = p.Health - dmg + }else { + p.State = DeadState{} + p.Health = 0 + } +} + +type DeadState struct {} + +func (DeadState)Heal(P *Player) error{ + return errors.New("you are dead") +} + +func (DeadState)Hurt(P *Player ,dmg int){} + +// context +type Player struct { + Health int + MaxHealth int + State PlayerState +} + +func (p *Player)HealPlayer()error{ + return p.State.Heal(p) +} + +func (p *Player)HurtPlayer(damage int){ + fmt.Printf("damage %d\n" ,damage) + p.State.Hurt(p ,damage) +} + +//func main(){ +// player := &Player{ +// Health:100, +// MaxHealth:100, +// State:HealthyState{}, +// } +// +// rand.Seed(time.Now().UnixNano()) +// for i:=0 ;i<10 ;i++{ +// if err := player.HealPlayer();err != nil{ +// fmt.Println(err) +// break +// } +// player.HurtPlayer(rand.Intn(30)) +// } +// /* +// output: +// damage 28 +// healing from 72 to 77 +// damage 29 +// healing from 48 to 53 +// damage 15 +// healing from 38 to 43 +// damage 1 +// healing from 42 to 47 +// damage 19 +// healing from 28 to 33 +// damage 27 +// healing from 6 to 11 +// damage 16 +// you are dead +// */ +//} From 285e22630d1583d5d410b1f46b87ee40b919567e Mon Sep 17 00:00:00 2001 From: nynicg Date: Sat, 4 May 2019 10:03:01 +0800 Subject: [PATCH 10/19] visitor pattern --- README.md | 6 +- behavioral/visitor/main.go | 110 +++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 behavioral/visitor/main.go diff --git a/README.md b/README.md index 6b76f10..3850325 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,10 @@ A curated collection of idiomatic design & application patterns for Go language. | [Memento](/behavioral/memento/main.go) | Generate an opaque token that can be used to go back to a previous state | ✔ | | [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ | | [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ | -| [State](/behavioral/state.md) | Encapsulates varying behavior for the same object based on its internal state | ✔ | +| [State](/behavioral/state/main.go) | Encapsulates varying behavior for the same object based on its internal state | ✔ | | [Strategy](/behavioral/strategy.md) | Enables an algorithm's behavior to be selected at runtime | ✔ | -| [Template](/behavioral/template.md) | Defines a skeleton class which defers some methods to subclasses | ✔ | -| [Visitor](/behavioral/visitor.md) | Separates an algorithm from an object on which it operates | ✘ | +| [Template](/behavioral/template/main.go) | Defines a skeleton class which defers some methods to subclasses | ✔ | +| [Visitor](/behavioral/visitor/main.go) | Separates an algorithm from an object on which it operates | ✔ | ## Synchronization Patterns diff --git a/behavioral/visitor/main.go b/behavioral/visitor/main.go new file mode 100644 index 0000000..474c668 --- /dev/null +++ b/behavioral/visitor/main.go @@ -0,0 +1,110 @@ +// 访问者模式 visitor pattern. +// 该模式用于将数据结构和操作进行分离,同样用于分离操作的还有策略模式(strategy pattern),但两者存在侧重点的不同. +// 访问者模式侧重于扩展访问的方法类型,是为了对某一个类及其子类的访问方式进行扩展,允许增加更多不同的访问者,但不宜增加更多的Host. +// 以下以实体A(仅有玩家、NPC、物体三类)被访问(查看信息、发起挑战等,此处可扩展)的过程 +package main + +import "log" + +// 如果这里有更多的新类型Host需要扩展,则不宜使用访问者模式 +type Host interface { + Accept(Visitor) +} + +type PlayerHost struct { + Name string + Level int +} + +func (p PlayerHost)Accept(v Visitor){ + v.VisitPlayer(p) +} + +type NPCHost struct { + Name string + IsImmortal bool +} + +func (n NPCHost)Accept(v Visitor){ + v.VisitNPC(n) +} + +type ObjectHost struct { + Name string + Price int +} + +func (o ObjectHost)Accept(v Visitor){ + v.VisitObject(o) +} + +type Visitor interface { + VisitPlayer(PlayerHost) + VisitNPC(NPCHost) + VisitObject(ObjectHost) +} + +// 访问者允许有不同类型的访问者 +// 仅查看信息的访问者 +type InfoVisitor struct {} + +func (InfoVisitor) VisitPlayer(p PlayerHost) { + log.Printf("Player -> Name:%s ,Level:%d\n" ,p.Name ,p.Level) +} + +func (InfoVisitor) VisitNPC(n NPCHost) { + log.Printf("NPC -> Name:%s ,Immortal:%v\n" ,n.Name ,n.IsImmortal) +} + +func (InfoVisitor) VisitObject(o ObjectHost) { + log.Printf("Object -> Name:%s ,Price:%d\n" ,o.Name ,o.Price) +} + +// 发起攻击的访问者 +type AggressiveVisitor struct {} + +func (AggressiveVisitor) VisitPlayer(p PlayerHost) { + log.Printf("Attack %s\n" ,p.Name) +} + +func (AggressiveVisitor) VisitNPC(n NPCHost) { + log.Printf("Attack NPC %s\n" ,n.Name) +} + +func (AggressiveVisitor) VisitObject(o ObjectHost) { + log.Printf("Unsupported target %s\n" ,o.Name) +} + +func main(){ + infoVst := InfoVisitor{} + agrVst := AggressiveVisitor{} + + pA := PlayerHost{"icg" ,1} + pB := PlayerHost{"sz" ,2} + npc := NPCHost{"nyn" ,true} + obj := ObjectHost{"cake" ,19} + + hostList := []Host{pA ,npc ,obj ,pB} + + for _ ,v := range hostList{ + v.Accept(infoVst) + } + println() + for _ ,v := range hostList{ + v.Accept(agrVst) + } + /* + output: + 2019/05/04 10:00:49 Player -> Name:icg ,Level:1 + 2019/05/04 10:00:49 NPC -> Name:nyn ,Immortal:true + 2019/05/04 10:00:49 Object -> Name:cake ,Price:19 + 2019/05/04 10:00:49 Player -> Name:sz ,Level:2 + + 2019/05/04 10:00:49 Attack icg + 2019/05/04 10:00:49 Attack NPC nyn + 2019/05/04 10:00:49 Unsupported target cake + 2019/05/04 10:00:49 Attack sz + */ + +} + From 4f002c767b767fd98bf4286d01d7234b3f0f5681 Mon Sep 17 00:00:00 2001 From: nynicg Date: Sun, 5 May 2019 15:23:17 +0800 Subject: [PATCH 11/19] bridge pattern --- README.md | 2 +- structural/bridge/main.go | 91 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 structural/bridge/main.go diff --git a/README.md b/README.md index 3850325..11d4e51 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ A curated collection of idiomatic design & application patterns for Go language. | Pattern | Description | Status | |:-------:|:----------- |:------:| -| [Bridge](/structural/bridge.md) | Decouples an interface from its implementation so that the two can vary independently | ✘ | +| [Bridge](/structural/bridge/main.go) | Decouples an interface from its implementation so that the two can vary independently | ✔ | | [Composite](/structural/composite.md) | Encapsulates and provides access to a number of different objects | ✘ | | [Decorator](/structural/decorator.md) | Adds behavior to an object, statically or dynamically | ✔ | | [Facade](/structural/facade.md) | Uses one type as an API to a number of others | ✘ | diff --git a/structural/bridge/main.go b/structural/bridge/main.go new file mode 100644 index 0000000..f0c0561 --- /dev/null +++ b/structural/bridge/main.go @@ -0,0 +1,91 @@ +// 桥接模式 bridge pattern. +// 桥接模式与策略模式有很多相似之处,原因在于他们都将行为交给了另一个接口实现, +// 桥接解决的是A+M、B+N、A+N等这样的调用者和行为的组合问题,是将不匹配的接口相组合,使之能够被统一的调用,一旦组合运行时一般不会发生变化. +// 策略模式则是为了动态的扩展,改变算法.本质上说桥接是结构模式策略是行为模式,侧重的分别是结构的组合和结构之间的通信 +package main + +// abstraction +type VehicleAbstraction interface { + Run() + MaxSpeed() int +} + +// refined abstraction +type Truck struct { + Driver DriverImplementor + maxSpeed int +} + +func (t Truck)Run(){ + println("truck begin to move...") + t.Driver.Drive(t) +} + +func (t Truck)MaxSpeed() int{ + return t.maxSpeed +} + +// refined abstraction +type Car struct { + Driver DriverImplementor + maxSpeed int +} + +func (c Car)Run(){ + println("car begin to move...") + c.Driver.Drive(c) +} + +func (c Car)MaxSpeed() int{ + return c.maxSpeed +} + +// implementor +type DriverImplementor interface { + Drive(vi VehicleAbstraction) +} + +// concrete implementor +type RookieDriver struct {} + +func (RookieDriver) Drive(vi VehicleAbstraction) { + println("rookie driver -> speed" ,vi.MaxSpeed() >> 1 ,"km/h") +} + +// concrete implementor +type OldDriver struct {} + +func (OldDriver)Drive(vi VehicleAbstraction){ + println("old driver -> speed" ,vi.MaxSpeed() ,"km/h") +} + +func main(){ + old := OldDriver{} + rk := RookieDriver{} + v1 := Truck{old ,60} + v2 := Car{old ,130} + v3 := Truck{rk ,60} + v4 := Car{rk ,130} + list := []VehicleAbstraction{v1 ,v2 ,v3 ,v4} + for _ ,v := range list{ + v.Run() + } + /* + output: + truck begin to move... + old driver -> speed 60 km/h + car begin to move... + old driver -> speed 130 km/h + truck begin to move... + rookie driver -> speed 30 km/h + car begin to move... + rookie driver -> speed 65 km/h + */ + +} + + + + + + From 98163f11793d94e535f1dfea8995e2eaea0f853f Mon Sep 17 00:00:00 2001 From: nynicg Date: Sun, 5 May 2019 16:08:55 +0800 Subject: [PATCH 12/19] composite pattern --- README.md | 2 +- structural/composite/main.go | 68 ++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 structural/composite/main.go diff --git a/README.md b/README.md index 11d4e51..552ec2a 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ A curated collection of idiomatic design & application patterns for Go language. | Pattern | Description | Status | |:-------:|:----------- |:------:| | [Bridge](/structural/bridge/main.go) | Decouples an interface from its implementation so that the two can vary independently | ✔ | -| [Composite](/structural/composite.md) | Encapsulates and provides access to a number of different objects | ✘ | +| [Composite](/structural/composite/main.go) | Encapsulates and provides access to a number of different objects | ✔ | | [Decorator](/structural/decorator.md) | Adds behavior to an object, statically or dynamically | ✔ | | [Facade](/structural/facade.md) | Uses one type as an API to a number of others | ✘ | | [Flyweight](/structural/flyweight.md) | Reuses existing instances of objects with similar/identical state to minimize resource usage | ✘ | diff --git a/structural/composite/main.go b/structural/composite/main.go new file mode 100644 index 0000000..9f4e043 --- /dev/null +++ b/structural/composite/main.go @@ -0,0 +1,68 @@ +// 组合模式 composite pattern. +// 用于表示树形的结构,这里以一个web静态目录为例 +package main + +type File struct { + IsDir bool + Name string + ChildFile []*File +} + +func (f *File)AddChild(file ...*File){ + f.ChildFile = append(f.ChildFile ,file...) +} + +func checkFile(file *File) { + println("into dir ->" ,file.Name) + for _ ,v := range file.ChildFile{ + if v.IsDir{ + checkFile(v) + }else{ + println("dir ->" ,file.Name ,".fileName ->" ,v.Name) + } + } +} + +func main(){ + /* + static| + -js| + -jquery.js + -main| + -index.js + -login.js + -css| + -bootstrap.css + */ + static := &File{true ,"static" ,make([]*File ,0)} + js := &File{true ,"js" ,make([]*File ,0)} + css := &File{true ,"css" ,make([]*File ,0)} + static.AddChild(js ,css) + + jquery := &File{false ,"jquery.js" ,nil} + mjs := &File{true ,"main" ,make([]*File ,0)} + js.AddChild(jquery ,mjs) + + injs := &File{false ,"index.js" ,nil} + lojs := &File{false ,"login.js" ,nil} + mjs.AddChild(injs ,lojs) + + + btstrap := &File{false ,"bootstrap.css" ,nil} + css.AddChild(btstrap) + + checkFile(static) + /* + output: + into dir -> static + into dir -> js + dir -> js .fileName -> jquery.js + into dir -> main + dir -> main .fileName -> index.js + dir -> main .fileName -> login.js + into dir -> css + dir -> css .fileName -> bootstrap.css + */ +} + + From 280a0ab36ac4f3e05aa390943ad12e4d64cd801f Mon Sep 17 00:00:00 2001 From: nynicg Date: Sun, 5 May 2019 17:18:49 +0800 Subject: [PATCH 13/19] facade pattern --- README.md | 2 +- structural/facade/main.go | 52 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 structural/facade/main.go diff --git a/README.md b/README.md index 552ec2a..e6e2135 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ A curated collection of idiomatic design & application patterns for Go language. | [Bridge](/structural/bridge/main.go) | Decouples an interface from its implementation so that the two can vary independently | ✔ | | [Composite](/structural/composite/main.go) | Encapsulates and provides access to a number of different objects | ✔ | | [Decorator](/structural/decorator.md) | Adds behavior to an object, statically or dynamically | ✔ | -| [Facade](/structural/facade.md) | Uses one type as an API to a number of others | ✘ | +| [Facade](/structural/facade/main.go) | Uses one type as an API to a number of others | ✔ | | [Flyweight](/structural/flyweight.md) | Reuses existing instances of objects with similar/identical state to minimize resource usage | ✘ | | [Proxy](/structural/proxy.md) | Provides a surrogate for an object to control it's actions | ✔ | diff --git a/structural/facade/main.go b/structural/facade/main.go new file mode 100644 index 0000000..953e6fd --- /dev/null +++ b/structural/facade/main.go @@ -0,0 +1,52 @@ +// 外观模式 facade pattern. +// 为多个子模块提供一个统一的调用接口,子模块可以是同一接口的实现也可以不同. +// 实际上编写程序的时候很多地方不知不觉的会使用了模式. +// 这里以购买鸡蛋,牛奶,小麦粉为例,从代购处一次性购买三种而不需要分别访问三个商店 +package main + +type Shop interface { + Sell() +} + +type EggShop struct {} + +func (EggShop)Sell(){ + println("no more eggs left") +} + +type MilkShop struct {} + +func (MilkShop)Sell(){ + println("no more milk left") +} + +type WheatFlourShop struct {} + +func (WheatFlourShop)Sell(){ + println("no more wheat flour left") +} + +type DealerFacade struct { + EgShop Shop + MkShop Shop + WfShop Shop +} + +func (d DealerFacade)SellAll(){ + d.EgShop.Sell() + d.MkShop.Sell() + d.WfShop.Sell() +} + +func main(){ + dealer := DealerFacade{ + EggShop{}, + MilkShop{}, + WheatFlourShop{}, + } + dealer.SellAll() +} + + + + From 178e5eff4c8cafb6875321f05da324feb3de9aa9 Mon Sep 17 00:00:00 2001 From: nynicg Date: Sun, 5 May 2019 23:12:47 +0800 Subject: [PATCH 14/19] flyweight pattern --- README.md | 2 +- structural/flyweight/main.go | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 structural/flyweight/main.go diff --git a/README.md b/README.md index e6e2135..f1f0347 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ A curated collection of idiomatic design & application patterns for Go language. | [Composite](/structural/composite/main.go) | Encapsulates and provides access to a number of different objects | ✔ | | [Decorator](/structural/decorator.md) | Adds behavior to an object, statically or dynamically | ✔ | | [Facade](/structural/facade/main.go) | Uses one type as an API to a number of others | ✔ | -| [Flyweight](/structural/flyweight.md) | Reuses existing instances of objects with similar/identical state to minimize resource usage | ✘ | +| [Flyweight](/structural/flyweight/main.go) | Reuses existing instances of objects with similar/identical state to minimize resource usage | ✔ | | [Proxy](/structural/proxy.md) | Provides a surrogate for an object to control it's actions | ✔ | ## Behavioral Patterns diff --git a/structural/flyweight/main.go b/structural/flyweight/main.go new file mode 100644 index 0000000..7d3fc68 --- /dev/null +++ b/structural/flyweight/main.go @@ -0,0 +1,47 @@ +// 享元模式 flyweight pattern. +// 通过保存不同特征的实例以达到复用的效果,从而节省内存和优化性能. +// 与对象池模式的不同之处在于享元模式所保存的实例具有不同的特征,而对象池则全部是相同的实例. +// 这里以蛋糕为例,字段flavour为其味道,根据不同的制作者将不同的实例保存起来. +// 当实例的特征较少时,享元模式还可以和单例模式相结合. +package main + +type Cake struct { + Flavour string +} + +type CakeFactory struct { + Cakes map[string]Cake +} + +func (f CakeFactory)NewCake(flavour string)Cake{ + if c ,ok := f.Cakes[flavour];ok{ + println("get an existing" ,c.Flavour ,"cake from map") + }else{ + f.Cakes[flavour] = Cake{flavour} + println("put a new" ,flavour ,"cake into map") + } + return f.Cakes[flavour] +} + +func main(){ + factory := CakeFactory{make(map[string]Cake)} + + factory.NewCake("strawberry") + factory.NewCake("chocolates") + factory.NewCake("nynicg") + + factory.NewCake("strawberry") + factory.NewCake("nynicg") + factory.NewCake("chocolates") + /* + output: + put a new strawberry cake into map + put a new chocolates cake into map + put a new nynicg cake into map + get an existing strawberry cake from map + get an existing nynicg cake from map + get an existing chocolates cake from map + */ +} + + From ffbfc177a7e7932aa843339a6ffecf6218e02a38 Mon Sep 17 00:00:00 2001 From: nynicg Date: Sun, 5 May 2019 23:42:21 +0800 Subject: [PATCH 15/19] update code --- structural/facade/main.go | 52 ++++++++++++++++++++++++++---------- structural/flyweight/main.go | 2 +- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/structural/facade/main.go b/structural/facade/main.go index 953e6fd..04c1a5b 100644 --- a/structural/facade/main.go +++ b/structural/facade/main.go @@ -1,29 +1,35 @@ // 外观模式 facade pattern. // 为多个子模块提供一个统一的调用接口,子模块可以是同一接口的实现也可以不同. -// 实际上编写程序的时候很多地方不知不觉的会使用了模式. -// 这里以购买鸡蛋,牛奶,小麦粉为例,从代购处一次性购买三种而不需要分别访问三个商店 +// 实际上编写程序的时候很多地方不知不觉的会使用该模式. +// 这里以购买鸡蛋,牛奶,小麦粉为例,从代购处一次性购买三种食材而不需要分别访问三个商店, +// SellAll()方法还可以将三处接口包装为原子操作,在购买失败时进行回滚 package main +import ( + "errors" + "fmt" +) + type Shop interface { - Sell() + Sell() error } type EggShop struct {} -func (EggShop)Sell(){ - println("no more eggs left") +func (EggShop)Sell() error{ + return errors.New("no more eggs left") } type MilkShop struct {} -func (MilkShop)Sell(){ - println("no more milk left") +func (MilkShop)Sell()error{ + return errors.New("no more milk left") } type WheatFlourShop struct {} -func (WheatFlourShop)Sell(){ - println("no more wheat flour left") +func (WheatFlourShop)Sell()error{ + return errors.New("no more wheat flour left") } type DealerFacade struct { @@ -32,10 +38,21 @@ type DealerFacade struct { WfShop Shop } -func (d DealerFacade)SellAll(){ - d.EgShop.Sell() - d.MkShop.Sell() - d.WfShop.Sell() +func (d DealerFacade)BuyAll(){ + //if e := d.EgShop.Sell();e != nil{ + // log.Println(e) + // RollBack() + //} + //... + e1 := d.EgShop.Sell() + e2 := d.MkShop.Sell() + e3 := d.WfShop.Sell() + if e1 == nil && e2 == nil && e3 == nil{ + //success + }else{ + //fail and rollback + fmt.Printf("error:\n%v\n%v\n%v" ,e1 ,e2 ,e3) + } } func main(){ @@ -44,7 +61,14 @@ func main(){ MilkShop{}, WheatFlourShop{}, } - dealer.SellAll() + dealer.BuyAll() + /* + output: + error: + no more eggs left + no more milk left + no more wheat flour left + */ } diff --git a/structural/flyweight/main.go b/structural/flyweight/main.go index 7d3fc68..9316897 100644 --- a/structural/flyweight/main.go +++ b/structural/flyweight/main.go @@ -1,7 +1,7 @@ // 享元模式 flyweight pattern. // 通过保存不同特征的实例以达到复用的效果,从而节省内存和优化性能. // 与对象池模式的不同之处在于享元模式所保存的实例具有不同的特征,而对象池则全部是相同的实例. -// 这里以蛋糕为例,字段flavour为其味道,根据不同的制作者将不同的实例保存起来. +// 这里以蛋糕为例,字段flavour为其味道,根据不同的味道作为不同的实例保存起来. // 当实例的特征较少时,享元模式还可以和单例模式相结合. package main From f41768955d8626453264d9c5d8a42c9ed298f845 Mon Sep 17 00:00:00 2001 From: nynicg Date: Mon, 6 May 2019 16:00:16 +0800 Subject: [PATCH 16/19] barrier pattern --- README.md | 2 +- concurrency/n_barrier/main.go | 130 ++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 concurrency/n_barrier/main.go diff --git a/README.md b/README.md index f1f0347..903e12b 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ A curated collection of idiomatic design & application patterns for Go language. | Pattern | Description | Status | |:-------:|:----------- |:------:| -| [N-Barrier](/concurrency/barrier.md) | Prevents a process from proceeding until all N processes reach to the barrier | ✘ | +| [N-Barrier](/concurrency/barrier/main.go) | Prevents a process from proceeding until all N processes reach to the barrier | ✔ | | [Bounded Parallelism](/concurrency/bounded_parallelism.md) | Completes large number of independent tasks with resource limits | ✔ | | [Broadcast](/concurrency/broadcast.md) | Transfers a message to all recipients simultaneously | ✘ | | [Coroutines](/concurrency/coroutine.md) | Subroutines that allow suspending and resuming execution at certain locations | ✘ | diff --git a/concurrency/n_barrier/main.go b/concurrency/n_barrier/main.go new file mode 100644 index 0000000..2957fa5 --- /dev/null +++ b/concurrency/n_barrier/main.go @@ -0,0 +1,130 @@ +package main + +import ( + "log" + "sync" +) + +type IBarrier interface { + Await() error +} + +type Barrier struct { + cond *sync.Cond + gos uint + curgos uint +} + +func NewBarrier(syncGos uint)*Barrier{ + if syncGos < 1{ + panic("min 1") + } + l := &sync.Mutex{} + c := sync.NewCond(l) + return &Barrier{ + cond:c, + gos:syncGos, + } +} + +func (b *Barrier)Await() error{ + b.cond.L.Lock() + defer b.cond.L.Unlock() + b.curgos++ + if b.gos != b.curgos{ + b.cond.Wait() + }else{ + b.curgos = 0 + b.cond.Broadcast() + } + return nil +} + + + +func main(){ + var b IBarrier + wg := &sync.WaitGroup{} + gos := 10 + wg.Add(gos) + b = NewBarrier(uint(gos)) + for i:=0;i Date: Mon, 6 May 2019 16:02:07 +0800 Subject: [PATCH 17/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 903e12b..5d1102e 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ A curated collection of idiomatic design & application patterns for Go language. | Pattern | Description | Status | |:-------:|:----------- |:------:| -| [N-Barrier](/concurrency/barrier/main.go) | Prevents a process from proceeding until all N processes reach to the barrier | ✔ | +| [N-Barrier](/concurrency/n_barrier/main.go) | Prevents a process from proceeding until all N processes reach to the barrier | ✔ | | [Bounded Parallelism](/concurrency/bounded_parallelism.md) | Completes large number of independent tasks with resource limits | ✔ | | [Broadcast](/concurrency/broadcast.md) | Transfers a message to all recipients simultaneously | ✘ | | [Coroutines](/concurrency/coroutine.md) | Subroutines that allow suspending and resuming execution at certain locations | ✘ | From 996819084081c1bf3cc3f9486b570e3112ff3d30 Mon Sep 17 00:00:00 2001 From: nynicg Date: Fri, 10 May 2019 14:57:25 +0800 Subject: [PATCH 18/19] barrier pattern --- concurrency/n_barrier/main.go | 141 +++++++++++++--------------------- 1 file changed, 52 insertions(+), 89 deletions(-) diff --git a/concurrency/n_barrier/main.go b/concurrency/n_barrier/main.go index 2957fa5..984e1f7 100644 --- a/concurrency/n_barrier/main.go +++ b/concurrency/n_barrier/main.go @@ -6,40 +6,69 @@ import ( ) type IBarrier interface { + // error for timeout if need Await() error } -type Barrier struct { - cond *sync.Cond - gos uint - curgos uint + +// once +type ChanBarrier struct { + gos int + curGos int + ch chan struct{} + m sync.Mutex } -func NewBarrier(syncGos uint)*Barrier{ - if syncGos < 1{ - panic("min 1") - } - l := &sync.Mutex{} - c := sync.NewCond(l) - return &Barrier{ - cond:c, - gos:syncGos, +func NewChanBarrier(gos int)*ChanBarrier{ + return &ChanBarrier{ + gos:gos, + ch:make(chan struct{}), } } -func (b *Barrier)Await() error{ - b.cond.L.Lock() - defer b.cond.L.Unlock() - b.curgos++ - if b.gos != b.curgos{ - b.cond.Wait() +func (c *ChanBarrier) Await() error { + c.m.Lock() + if c.curGos++;c.gos != c.curGos{ + c.m.Unlock() + <- c.ch }else{ - b.curgos = 0 - b.cond.Broadcast() + c.m.Unlock() + close(c.ch) } return nil } +//type Barrier struct { +// cond *sync.Cond +// gos uint +// curgos uint +//} +// +//func NewBarrier(syncGos uint)*Barrier{ +// if syncGos < 1{ +// panic("min 1") +// } +// l := &sync.Mutex{} +// c := sync.NewCond(l) +// return &Barrier{ +// cond:c, +// gos:syncGos, +// } +//} +// +//func (b *Barrier)Await() error{ +// b.cond.L.Lock() +// defer b.cond.L.Unlock() +// b.curgos++ +// if b.gos != b.curgos{ +// b.cond.Wait() +// }else{ +// b.curgos = 0 +// b.cond.Broadcast() +// } +// return nil +//} + func main(){ @@ -47,7 +76,8 @@ func main(){ wg := &sync.WaitGroup{} gos := 10 wg.Add(gos) - b = NewBarrier(uint(gos)) + //b = NewBarrier(uint(gos)) + b = NewChanBarrier(gos) for i:=0;i Date: Fri, 10 May 2019 15:11:04 +0800 Subject: [PATCH 19/19] barrier pattern --- concurrency/n_barrier/main.go | 39 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/concurrency/n_barrier/main.go b/concurrency/n_barrier/main.go index 984e1f7..45276a2 100644 --- a/concurrency/n_barrier/main.go +++ b/concurrency/n_barrier/main.go @@ -13,27 +13,28 @@ type IBarrier interface { // once type ChanBarrier struct { - gos int - curGos int - ch chan struct{} - m sync.Mutex + waitCh chan struct{} + sign chan struct{} } func NewChanBarrier(gos int)*ChanBarrier{ - return &ChanBarrier{ - gos:gos, - ch:make(chan struct{}), + b := &ChanBarrier{ + waitCh:make(chan struct{} ,gos-1), + sign:make(chan struct{}), } + for i:=0;i