merge other commits for petterns
This commit is contained in:
Edward 2020-05-03 01:17:27 +08:00
commit a1e8af8392
16 changed files with 1203 additions and 12 deletions

View File

@ -25,27 +25,27 @@ A curated collection of idiomatic design & application patterns for Go language.
| Pattern | Description | Status | | 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 | ✘ | | [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 | ✔ | | [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 | | | [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 | ✔ | | [Proxy](/structural/proxy.md) | Provides a surrogate for an object to control it's actions | ✔ |
## Behavioral Patterns ## Behavioral Patterns
| Pattern | Description | Status | | 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/main.go) | 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/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 | ✘ | | [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 | ✔ | | [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 | ✘ | | [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 | ✔ | | [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/main.go) | Defines a skeleton class which defers some methods to subclasses | ✔ |
| [Visitor](/behavioral/visitor.md) | Separates an algorithm from an object on which it operates | ✘ | | [Visitor](/behavioral/visitor/main.go) | Separates an algorithm from an object on which it operates | ✔ |
## Synchronization Patterns ## Synchronization Patterns
@ -61,7 +61,7 @@ A curated collection of idiomatic design & application patterns for Go language.
| Pattern | Description | Status | | Pattern | Description | Status |
|:-------:|:----------- |:------:| |:-------:|:----------- |:------:|
| [N-Barrier](/concurrency/barrier.md) | 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 | ✔ | | [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 | ✘ | | [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 | ✘ | | [Coroutines](/concurrency/coroutine.md) | Subroutines that allow suspending and resuming execution at certain locations | ✘ |

View File

@ -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)
}

View File

@ -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{}
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
*/
}

View File

@ -0,0 +1,82 @@
// 命令模式(command pattern)主要解耦了行为和接收者,使之可以任意组合为一个完整的命令,并在合适的时候被调用
// 主要分为四个部分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 ,escp)
invoker.CallCommands()
// output:
/*
icg opened fire
icg escape
icg escape
icg opened fire
icg escape
*/
}

View File

@ -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
*/
}

View File

@ -0,0 +1,92 @@
// 备忘录模式 memento pattern
// 在不影响原结构封装的情况下,能够暂时保存一个结构的状态,并能够恢复
// 这里是一个游戏存档的例子,尝试保存玩家当前位置,并在读档的时候恢复
package main
import (
"container/list"
"log"
)
// originator
type Player struct {
// 需要记录的数据可以考虑单独封装
// type Pos struct{X,Y int}
X,Y int
// other info
Name string
}
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
}
// memento
type PlayerMemento struct {
X,Y int
}
// caretaker
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)
/*
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
*/
}

84
behavioral/state/main.go Normal file
View File

@ -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
*/
}

118
behavioral/state/problem.go Normal file
View File

@ -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
// */
//}

View File

@ -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
}

101
behavioral/template/main.go Normal file
View File

@ -0,0 +1,101 @@
// 存疑的部分.
// 模板模式和策略模式在很多时候给人感觉基本可以划等号,事实上两者侧重的方向不同.
// 策略模式倾向于通过改变结构的属性从而改变算法,模板模式则倾向于事先定义一个处理的流程,该流程是可以被整体替换的.
// 个人认为应该保证模板模式下的结构体应当独立出来,每个流程单独被调用.
// 感觉以下两种写法都有点别扭,待指正
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()
//}

110
behavioral/visitor/main.go Normal file
View File

@ -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
*/
}

View File

@ -0,0 +1,94 @@
package main
import (
"log"
"sync"
)
type IBarrier interface {
// error for timeout if need
Await() error
}
// once
type ChanBarrier struct {
waitCh chan struct{}
sign chan struct{}
}
func NewChanBarrier(gos int)*ChanBarrier{
b := &ChanBarrier{
waitCh:make(chan struct{} ,gos-1),
sign:make(chan struct{}),
}
for i:=0;i<gos-1;i++{
b.waitCh <- struct{}{}
}
return b
}
func (b *ChanBarrier) Await() error {
select {
case <- b.waitCh:
<- b.sign
default:
close(b.sign)
close(b.waitCh)
}
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(){
var b IBarrier
wg := &sync.WaitGroup{}
gos := 10
wg.Add(gos)
//b = NewBarrier(uint(gos))
b = NewChanBarrier(gos)
for i:=0;i<gos ;i++ {
go func(n int) {
log.Println(n ,"await")
if err := b.Await();err != nil{
log.Println(err)
}
log.Println(n ,"pass")
wg.Done()
}(i)
}
wg.Wait()
}

91
structural/bridge/main.go Normal file
View File

@ -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
*/
}

View File

@ -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
*/
}

76
structural/facade/main.go Normal file
View File

@ -0,0 +1,76 @@
// 外观模式 facade pattern.
// 为多个子模块提供一个统一的调用接口,子模块可以是同一接口的实现也可以不同.
// 实际上编写程序的时候很多地方不知不觉的会使用该模式.
// 这里以购买鸡蛋,牛奶,小麦粉为例,从代购处一次性购买三种食材而不需要分别访问三个商店,
// SellAll()方法还可以将三处接口包装为原子操作,在购买失败时进行回滚
package main
import (
"errors"
"fmt"
)
type Shop interface {
Sell() error
}
type EggShop struct {}
func (EggShop)Sell() error{
return errors.New("no more eggs left")
}
type MilkShop struct {}
func (MilkShop)Sell()error{
return errors.New("no more milk left")
}
type WheatFlourShop struct {}
func (WheatFlourShop)Sell()error{
return errors.New("no more wheat flour left")
}
type DealerFacade struct {
EgShop Shop
MkShop Shop
WfShop Shop
}
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(){
dealer := DealerFacade{
EggShop{},
MilkShop{},
WheatFlourShop{},
}
dealer.BuyAll()
/*
output:
error:
no more eggs left
no more milk left
no more wheat flour left
*/
}

View File

@ -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
*/
}