├── .idea ├── algo.iml ├── encodings.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── BasicGo ├── GoRoutine │ ├── Goroutine.go │ └── Goroutine_test.go ├── defer │ ├── defer.go │ └── defer_test.go └── reflect │ ├── Reflect.go │ └── Reflect_test.go ├── BinarySearch ├── README.md ├── Tree.go └── Tree_test.go ├── DesignPatterns ├── 7Rules.go ├── 7Rules_test.go ├── BehavioralType │ ├── Command.go │ ├── Command_test.go │ ├── Docs │ │ ├── 中介者模式.md │ │ ├── 命令模式.md │ │ ├── 备忘录模式.md │ │ ├── 模板方法模式.md │ │ ├── 状态模式.md │ │ ├── 策略模式.md │ │ ├── 观察者模式.md │ │ ├── 解释器模式.md │ │ ├── 责任链模式.md │ │ └── 迭代器模式.md │ ├── Handler.go │ ├── Handler_test.go │ ├── Interpreter.go │ ├── Interpreter_test.go │ ├── Iterator.go │ ├── Iterator_test.go │ ├── Mediator.go │ ├── Mediator_test.go │ ├── Memento.go │ ├── Memento_test.go │ ├── Observer.go │ ├── Observer_test.go │ ├── State.go │ ├── State_test.go │ ├── Strategy.go │ ├── Strategy_test.go │ ├── Template.go │ └── Template_test.go ├── Compound.go ├── Compound_test.go ├── CreativeType │ ├── AbstractFactory.go │ ├── Builder.go │ ├── Docs │ │ ├── 单例模式.md │ │ ├── 原型模式.md │ │ ├── 建造者模式.md │ │ ├── 抽象工厂.md │ │ └── 简单工厂模式.md │ ├── Prototype.go │ ├── Prototype_test.go │ ├── SimpleFactory.go │ ├── SimpleFactory_test.go │ ├── Singleton.go │ ├── Singleton_test.go │ ├── abs_test.go │ └── builder_test.go ├── README.MD ├── StructuralType │ ├── Bridge.go │ ├── Bridge_test.go │ ├── Component.go │ ├── Component_test.go │ ├── Decorator.go │ ├── Decorator_test.go │ ├── Docs │ │ ├── 享元模式.md │ │ ├── 代理模式.md │ │ ├── 修饰器模式.md │ │ ├── 外观模式.md │ │ ├── 桥接模式.md │ │ ├── 组合模式.md │ │ ├── 过滤模式.md │ │ └── 适配器模式.md │ ├── Facade.go │ ├── Facade_test.go │ ├── Filter.go │ ├── Filter_test.go │ ├── Flyweight.go │ ├── Flyweight_test.go │ ├── Proxy.go │ ├── Proxy_test.go │ ├── Wrapper.go │ └── Wrapper_test.go └── 七大设计原则.md ├── DoubleLinked ├── FIFO.go ├── FIFO_test.go ├── LFU.go ├── LFU_test.go ├── LRU.go ├── LRU_test.go ├── List.go └── test.txt ├── Graph_algo ├── .idea │ ├── Graph_algo.iml │ ├── misc.xml │ ├── modules.xml │ ├── vcs.xml │ └── workspace.xml ├── Adj │ ├── Hash.go │ ├── Matrix.go │ ├── Matrix_test.go │ ├── Table.go │ └── Table_test.go ├── BFS │ └── traverse.go ├── DFS │ └── CC.go ├── README.md ├── g.txt ├── g2.txt ├── g2_noCycle.txt ├── leetcode │ ├── 1091.go │ ├── 1091_test.go │ ├── 200.go │ ├── 4LWater.go │ ├── 4LWater_test.go │ ├── 695.go │ ├── 695_2.go │ ├── 695_test.go │ ├── 752.go │ ├── 785.go │ ├── shuffle.go │ └── shuffle_test.go ├── main.go ├── notBip.txt └── search │ ├── BipartitionDetection.go │ ├── Cycle.go │ ├── Find.go │ └── SingleSourcePath.go ├── Heap ├── Arrar_test.go ├── Array.go ├── PriorityQueue.go └── README.md ├── LICENSE ├── Linked ├── 1.1 Reverse.go ├── 1.10 RemoveNode.go ├── 1.11 CheckIntersect.go ├── 1.2 RemoveDup.go ├── 1.3AddTwoList.go ├── 1.4MiddleReverse.go ├── 1.5 FindLastK.go ├── 1.6 FindEntry.go ├── 1.7 ReverseTwo.go ├── 1.8 ReverseK.go ├── 1.9 MeegeTwoList.go ├── List.go ├── List_test.go ├── README.md └── go语言实现链表相关题目.md ├── OSExam ├── FCFS.go ├── FCFS_test.go ├── FP.go ├── FP_test.go ├── Process.go ├── SJF.go ├── SJF_test.go ├── fileSystem.go ├── test.txt └── test1.txt ├── README.md ├── Red-Black ├── README.md ├── Tree.go ├── Tree_test.go ├── c.out └── coverage.html ├── Segment ├── README.md ├── SegmentTree_test.go └── Tree.go ├── Set ├── BST.go └── List.go ├── Sorts ├── Bubble.go ├── Bucket.go ├── Insert.go ├── Merge.go ├── Quick.go ├── Select.go ├── Shell.go └── Sort_test.go ├── Trie ├── README.md ├── Trie.go ├── Trie_test.go └── pride-and-prejudice.txt ├── Union ├── Find.go ├── Find_test.go └── README.md ├── Utils ├── Interfaces.go └── Interfaces │ └── Interfaces.go ├── com_test.go ├── combine.go ├── main ├── 622.go └── main.go ├── pkg └── mod │ └── cache │ └── lock ├── queue └── queue.go ├── skiplists ├── SkipLists.go └── SkipLists_test.go └── stack ├── stack.go └── stack_test.go /.idea/algo.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /BasicGo/GoRoutine/Goroutine_test.go: -------------------------------------------------------------------------------- 1 | package GoRoutine 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "sync" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | func TestThread(t *testing.T) { 12 | //Thread() 13 | //ThreadWrong() 14 | //t.Log(CounterWrong()) 15 | //t.Log(Counter()) 16 | //t.Log(WaitGroupExam()) 17 | //ret := AsnyService() 18 | //otherTask() 19 | //fmt.Println(<-ret) 20 | select { 21 | case ret := <-AsnyService(): 22 | t.Log(ret) 23 | // 超时控制 24 | case <- time.After(time.Millisecond * 100): 25 | t.Error("time out") 26 | } 27 | } 28 | 29 | func TestConsumer(t *testing.T) { 30 | var wg sync.WaitGroup 31 | // 创造一个同步通道 32 | ch := make(chan int) 33 | // 创造一个异步通道 34 | // cha := make(chan int,3) 35 | wg.Add(1) 36 | go Producer(ch,&wg) 37 | for i := 0; i < 3; i++ { 38 | wg.Add(1) 39 | go Consumer(ch,&wg) 40 | } 41 | t.Log(runtime.NumGoroutine()) 42 | wg.Wait() 43 | } 44 | 45 | func TestCancel(t *testing.T) { 46 | Cancel() 47 | } 48 | 49 | func TestNewObjPool(t *testing.T) { 50 | pool := NewObjPool(10) 51 | 52 | for i := 0; i < 100; i++ { 53 | if v,err := pool.GetObj(time.Second);err!=nil{ 54 | t.Error(err) 55 | } else { 56 | fmt.Println(i) 57 | if err = pool.ReleaseObj(v); err != nil { 58 | t.Error(err) 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /BasicGo/defer/defer.go: -------------------------------------------------------------------------------- 1 | package _defer 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func Error() { 9 | // 这里我们使用recover函数进行修复 10 | defer func() { 11 | if err := recover(); err != nil { 12 | fmt.Println("Recovered from",err) 13 | } 14 | }() 15 | 16 | fmt.Println("Start") 17 | panic(errors.New("Something Wrong!")) 18 | } 19 | -------------------------------------------------------------------------------- /BasicGo/defer/defer_test.go: -------------------------------------------------------------------------------- 1 | package _defer 2 | 3 | import "testing" 4 | 5 | func TestError(t *testing.T) { 6 | Error() 7 | } 8 | -------------------------------------------------------------------------------- /BasicGo/reflect/Reflect.go: -------------------------------------------------------------------------------- 1 | package reflect 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // 反射编程测试 9 | func CheckType(v interface{}) { 10 | t := reflect.TypeOf(v) 11 | switch t.Kind() { 12 | case reflect.Float32, reflect.Float64: 13 | fmt.Println("浮点数") 14 | case reflect.Int, reflect.Int32, reflect.Int64: 15 | fmt.Println("带符号整数") 16 | case reflect.Uint, reflect.Uint32, reflect.Uint64: 17 | fmt.Println("无符号整数") 18 | default: 19 | fmt.Println("Unknown",t) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /BasicGo/reflect/Reflect_test.go: -------------------------------------------------------------------------------- 1 | package reflect 2 | 3 | import "testing" 4 | 5 | func TestCheckType(t *testing.T) { 6 | var ( 7 | i int 8 | f float32 9 | d *float64 10 | s struct{} 11 | ) 12 | CheckType(i) 13 | CheckType(f) 14 | CheckType(d) 15 | CheckType(s) 16 | } 17 | -------------------------------------------------------------------------------- /BinarySearch/Tree_test.go: -------------------------------------------------------------------------------- 1 | package BinarySearch 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestTree(t *testing.T) { 9 | tree := &Tree{} 10 | fmt.Println(tree.IsEmpty()) 11 | var arr [6]int = [6]int{5,3,6,8,4,2} 12 | for _,v := range arr{ 13 | tree.AddE(v) 14 | } 15 | tree.PreOrder() 16 | tree.PreOrderNR() 17 | fmt.Println(tree.FindMax()) 18 | fmt.Println(tree.FindMin()) 19 | fmt.Println("能否找到5:",tree.Contains(5)) 20 | fmt.Println(tree.DelMax()) 21 | fmt.Println(tree.DelMin()) 22 | fmt.Println(tree.size) 23 | fmt.Println(tree) 24 | tree.Remove(5) 25 | fmt.Println(tree) 26 | } 27 | -------------------------------------------------------------------------------- /DesignPatterns/7Rules.go: -------------------------------------------------------------------------------- 1 | package DesignPatterns 2 | 3 | import "fmt" 4 | 5 | type ICar interface { 6 | // 车名 7 | GetName() string 8 | // 价格 9 | GetPrice() int 10 | } 11 | 12 | type BenzCar struct { 13 | name string 14 | price int 15 | } 16 | 17 | func (b BenzCar) GetName() string { 18 | return b.name 19 | } 20 | 21 | func (b BenzCar) GetPrice() int { 22 | return b.price 23 | } 24 | 25 | type FinanceBenzCar struct { 26 | BenzCar 27 | } 28 | 29 | 30 | func (b FinanceBenzCar) GetPrice() int { 31 | // 获取原价 32 | selfPrice := b.price 33 | var finance int 34 | if selfPrice >= 100 { 35 | finance = selfPrice + selfPrice*5/100 36 | } else if selfPrice >= 50 { 37 | finance = selfPrice + selfPrice*2/100 38 | } else { 39 | finance = selfPrice 40 | } 41 | return finance 42 | } 43 | 44 | type Girl struct { 45 | 46 | } 47 | 48 | type GroupLeader struct { 49 | girls []Girl 50 | } 51 | 52 | func (g GroupLeader) CountGirls () { 53 | fmt.Println("The sum of girls is ", len(g.girls)) 54 | } 55 | 56 | type Teacher struct { 57 | 58 | } 59 | 60 | func (t Teacher) Command(leader GroupLeader) { 61 | leader.CountGirls() 62 | } 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /DesignPatterns/7Rules_test.go: -------------------------------------------------------------------------------- 1 | package DesignPatterns 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestBenzCar_GetName(t *testing.T) { 9 | var ( 10 | list []ICar 11 | ) 12 | list = []ICar{} 13 | list = append(list,&FinanceBenzCar{BenzCar{"迈巴赫",99}}) 14 | list = append(list,&FinanceBenzCar{BenzCar{"AMG",200}}) 15 | list = append(list,&FinanceBenzCar{BenzCar{"V",40}}) 16 | for _,v := range list { 17 | fmt.Println("车名:",v.GetName(),"\t价格:",v.GetPrice()) 18 | } 19 | 20 | //person := Person{ani:&Rubbit{}} 21 | //person.WalkAnimal() 22 | } 23 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Command.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "fmt" 4 | 5 | type command interface { 6 | Execute() 7 | } 8 | type TV struct {} 9 | 10 | func (tv *TV) Open() { 11 | fmt.Println("打开电视") 12 | } 13 | func (tv *TV) Close() { 14 | fmt.Println("关闭电视") 15 | } 16 | func (tv *TV)Change() { 17 | fmt.Println("换台") 18 | } 19 | 20 | // 接受者 21 | type OpenTvCommand struct { 22 | tv *TV 23 | } 24 | 25 | func (o *OpenTvCommand) Execute() { 26 | o.tv.Open() 27 | } 28 | type CloseTvCommand struct { 29 | tv *TV 30 | } 31 | 32 | func (c *CloseTvCommand) Execute() { 33 | c.tv.Close() 34 | } 35 | 36 | type ChangeTvCommand struct { 37 | tv *TV 38 | } 39 | 40 | func (c *ChangeTvCommand) Execute() { 41 | c.tv.Change() 42 | } 43 | 44 | type TVRemote struct { 45 | open *OpenTvCommand 46 | change *ChangeTvCommand 47 | close *CloseTvCommand 48 | } 49 | 50 | func (tv *TVRemote) Open () { 51 | tv.open.Execute() 52 | } 53 | func (tv *TVRemote) Change() { 54 | tv.change.Execute() 55 | } 56 | func (tv *TVRemote) Close () { 57 | tv.close.Execute() 58 | } 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Command_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestConcreteCommand_DoExec(t *testing.T) { 8 | // 创建接收者 9 | rece := &TV{} 10 | // 创建命令对象 11 | openComm := &OpenTvCommand{rece} 12 | changeComm := &ChangeTvCommand{rece} 13 | closeComm := &CloseTvCommand{rece} 14 | 15 | // 创建请求者,把命令对象设置进去 16 | tvR := &TVRemote{ 17 | open: openComm, 18 | change: changeComm, 19 | close: closeComm, 20 | } 21 | tvR.Open() 22 | tvR.Change() 23 | tvR.Close() 24 | } 25 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Docs/命令模式.md: -------------------------------------------------------------------------------- 1 | ## 命令模式 2 | 3 | ### 定义 4 | 5 | 命令模式( Command Pattern)又称为行动( Action)模式或交易( Transaction)模式。 6 | 7 | 命令模式的英文定义是: 8 | 9 | > Encapsulate a request as an object, thereby letting you parameterize clients withdifferent requests, queue or log requests, and support undoable operations. 10 | 11 | 意思是:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或,者记录请求日志,可以提供命令的撤销和恢复功能。 12 | 13 | 简单来说,命令模式就是将发送者、接收者和调用命令封装成对象,客户端调用的时候可以选择不同的对象,从而实现发送者和接收者的完全解耦。 14 | 15 | ### 类图 16 | 17 | ![](https://img.mukewang.com/5db7e6ee0001c73906500263.png) 18 | 19 | 命令模式包含如下角色: 20 | 21 | ●命令接口(Command)角色:该角色声明一一个接口,定义需要执行的命令; 22 | 23 | ●具体命令实现类( Concrete Command) 角色:该角色定义一个接收者和行为之间的弱耦合,实现命令方法,并调用接收者的相应操作; 24 | 25 | ●调用者(Invoker) 角色:该角色负责调用命令对象执行请求; 26 | 27 | ●接收者( Receiver) 角色:该角色负责具体实施和执行请求动作(方法) ; 28 | 29 | ●客户端(Client)角色:串连执行整个流程。 30 | 31 | ### 优缺点 32 | 33 | 命令模式的优点: 34 | 35 | * 类间解耦:调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需要调用Command中的execute()方法即可,不需要了解是哪个接收者执行; 36 | * 可扩展性: Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合。 37 | 38 | 命令模式的缺点: 39 | 40 | * 使用命令模式会导致系统有过多的具体命令类,因为针对每一一个命令都需要设计一一个具体命令类。 41 | 42 | ### 应用场景 43 | 命令模式的典型应用场景如下: 44 | * 系统需要支持命令的撤销(undo),命令对象可以把状态存储起来,等到客户端需要撤销时,可以调用undo() 方法,将命令所产生的效果撤销; 45 | * 系统需要支持命令的撤销(Undo )操作和恢复( Redo)操作; 46 | * 系统需要将一-组操作组合在- 起,使用命令模式来实现, 可以很方便的增加新的命令。 47 | 48 | ### 使用实例:遥控器 49 | 50 | 51 | ```go 52 | import "fmt" 53 | // 命令接口和实现类 54 | type command interface { 55 | Execute() 56 | } 57 | 58 | type OpenTvCommand struct { 59 | tv *TV 60 | } 61 | 62 | func (o *OpenTvCommand) Execute() { 63 | o.tv.Open() 64 | } 65 | 66 | type CloseTvCommand struct { 67 | tv *TV 68 | } 69 | 70 | func (c *CloseTvCommand) Execute() { 71 | c.tv.Close() 72 | } 73 | 74 | type ChangeTvCommand struct { 75 | tv *TV 76 | } 77 | 78 | func (c *ChangeTvCommand) Execute() { 79 | c.tv.Change() 80 | } 81 | // 命令的接收者 82 | type TV struct {} 83 | 84 | func (tv *TV) Open() { 85 | fmt.Println("打开电视") 86 | } 87 | func (tv *TV) Close() { 88 | fmt.Println("关闭电视") 89 | } 90 | func (tv *TV)Change() { 91 | fmt.Println("换台") 92 | } 93 | 94 | // 命令的执行者:向TV发起命令 95 | type TVRemote struct { 96 | open *OpenTvCommand 97 | change *ChangeTvCommand 98 | close *CloseTvCommand 99 | } 100 | 101 | func (tv *TVRemote) Open () { 102 | tv.open.Execute() 103 | } 104 | func (tv *TVRemote) Change() { 105 | tv.change.Execute() 106 | } 107 | func (tv *TVRemote) Close () { 108 | tv.close.Execute() 109 | } 110 | ``` 111 | 112 | 113 | ```go 114 | // 创建接收者 115 | rece := &TV{} 116 | // 创建命令对象 117 | openComm := &OpenTvCommand{rece} 118 | changeComm := &ChangeTvCommand{rece} 119 | closeComm := &CloseTvCommand{rece} 120 | 121 | // 创建请求者,把命令对象设置进去 122 | tvR := &TVRemote{ 123 | open: openComm, 124 | change: changeComm, 125 | close: closeComm, 126 | } 127 | tvR.Open() 128 | tvR.Change() 129 | tvR.Close() 130 | ``` 131 | 132 | 打开电视 133 | 换台 134 | 关闭电视 135 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Docs/备忘录模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 备忘录模式 4 | 5 | ### 模式的定义与特点 6 | 备忘录(Memento)模式的定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。 7 | 8 | 备忘录模式是一种对象行为型模式,其主要优点如下。 9 | * 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。 10 | * 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。 11 | * 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。 12 | 13 | 其主要缺点是:资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。 14 | 15 | ### 模式的结构与实现 16 | 备忘录模式的核心是设计备忘录类以及用于管理备忘录的管理者类,现在我们来学习其结构与实现。 17 | 1. 模式的结构 18 | 备忘录模式的主要角色如下。 19 | 1. 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。 20 | 2. 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。 21 | 3. 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。 22 | 23 | 24 | ### 备忘录模式的结构图 25 | 26 | ![](http://c.biancheng.net/uploads/allimg/181119/3-1Q119130413927.gif) 27 | 28 | ### 模式的应用场景 29 | 30 | 1. 需要保存与恢复数据的场景,如玩游戏时的中间结果的存档功能。 31 | 2. 需要提供一个可回滚操作的场景,如 Word、记事本、Photoshop,Eclipse 等软件在编辑时按 Ctrl+Z 组合键,还有数据库中事务操作。 32 | 33 | 34 | ```go 35 | // 备忘录 36 | type Memento struct { 37 | state string // 这里就是保存的状态 38 | } 39 | 40 | func (m *Memento) SetState(s string) { 41 | m.state = s 42 | } 43 | 44 | func (m *Memento) GetState() string { 45 | return m.state 46 | } 47 | ``` 48 | 49 | 50 | ```go 51 | // 发起人 52 | type Originator struct { 53 | state string // 这里就简单一点,要保存的状态就是一个字符串 54 | } 55 | 56 | func (o *Originator) SetState(s string) { 57 | o.state = s 58 | } 59 | 60 | func (o *Originator) GetState() string { 61 | return o.state 62 | } 63 | 64 | // 这里就是规定了要保存的状态范围 65 | func (o *Originator) CreateMemento() *Memento { 66 | return &Memento{state: o.state} 67 | } 68 | ``` 69 | 70 | 71 | ```go 72 | // 负责人 73 | type Caretaker struct { 74 | memento *Memento 75 | } 76 | 77 | func (c *Caretaker) GetMemento() *Memento { 78 | return c.memento 79 | } 80 | 81 | func (c *Caretaker) SetMemento(m *Memento) { 82 | c.memento = m 83 | } 84 | ``` 85 | 86 | 87 | ```go 88 | import "fmt" 89 | // 创建一个发起人并设置初始状态 90 | // 此时与备忘录模式无关,只是模拟正常程序运行 91 | o := &Originator{state: "hello"} 92 | fmt.Println("当前状态:",o.GetState()) 93 | // 现在需要保存当前状态 94 | // 就创建一个负责人来设置(一般来说,对于一个对象的同一个备忘范围,应当只有一个负责人,这样方便做多状态多备忘管理) 95 | c := new(Caretaker) 96 | c.SetMemento(o.CreateMemento()) 97 | 98 | o.SetState("world") 99 | fmt.Println("更改当前状态:",o.GetState()) 100 | 101 | // 恢复备忘 102 | o.SetState(c.GetMemento().GetState()) 103 | fmt.Println("恢复后状态",o.GetState()) 104 | ``` 105 | 106 | 当前状态: hello 107 | 更改当前状态: world 108 | 恢复后状态 hello 109 | 110 | 111 | 112 | 113 | 114 | 22 115 | 116 | 117 | 118 | 119 | ```go 120 | 121 | ``` 122 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Docs/模板方法模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## 模板方法模式 5 | 6 | ### 定义 7 | 模板模式(Template Pattern )又被称作模板方法模式( Template Method Pattern),它是一种简单的、常见的且应用非常广泛的模式。 8 | 9 | 英文定义如下: 10 | 11 | > Define the skeleton of an algorithm in an operation, deferring some steps tosubclasses. Template Method lets subclasses redefine certain steps of analgorithm without changing the algorithm' S structure. 12 | 13 | 意思是:定义一个操作中的算法的框架,而将一些 步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。简单来说,就是为子类设计一个模板,以便在子类中可以复用这些方法。 14 | 15 | ### 类图 16 | 17 | ![](https://img.mukewang.com/5def3f750001ca0404790251.png) 18 | 19 | 模板模式包含如下角色: 20 | 21 | * 抽象模板(Abstract Template)角色:该角色定义一个或多个抽象操作,以便让子类实现;这些抽象操作是基本操作,是一个顶级逻辑的组成步骤,该角色还需要定义一个或几个模板方法(模板方法的介绍,请看下文) ; 22 | * 具体模板(Concrete Template) 角色:该角色实现抽象模板中定义的一个或多个抽象方法,每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法的不同实现,从而使得顶级逻辑的实现各不相同。 23 | 24 | ### 优缺点 25 | 26 | 模板模式的优点: 27 | * 提高了代码的复用性,将相同部分的代码放在抽象的父类中; 28 | * 提高了拓展性:将不同的代码放入不同的子类中,通过对子类的扩展增加新的行为;符合开闭原则:行为由父类控制,通过子类扩展新的行为。 29 | 模板模式的缺点: 30 | * 每个不同的行为都要新增一个子类来完成,抽象类中的抽象方法越多,子类增加成本就越高。而且新增的子类越多,系统就越复杂。 31 | 32 | ### 应用场景 33 | 模板模式的典型应用场景如下: 34 | 多个子类有公共方法,并且逻辑基本相同时; 35 | 36 | * 可以把重要的、复杂的、核心算法设计为模板方法,其他的相关细节功能则由各个子类实现; 37 | * 重构时,模板方法模式是-一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。 38 | 39 | ### 使用实例 40 | 以生活中.上班的过程为例,我们上班的通常流程是:起床洗漱->通勤(开车、坐公交、打车) 41 | ->到达公司。从以上步骤可以看出,只有通勤部分是不一样的,其他都一样,因为开车可能会 42 | 被限号,就只能打车或坐公交去公司了,下面我们用代码( 模板模式)来实现一下。 43 | 44 | 45 | 46 | ```go 47 | // 上班抽象模板接口 48 | type AbstractWork interface { 49 | // 由于go是面向组合的一种思维,从语言层不支持聚合,所以聚合需要自己把接口变量传入来实现 50 | GotoWork(work AbstractWork) 51 | Getup() 52 | Commute() 53 | Arrive() 54 | } 55 | // 上班抽象类 56 | type AbsClass struct {} 57 | 58 | func (a AbsClass) GotoWork(work AbstractWork) { 59 | a.Getup() 60 | work.Commute() 61 | a.Arrive() 62 | } 63 | 64 | func (a AbsClass) Getup() { 65 | fmt.Println("1. 起床") 66 | } 67 | 68 | func (a AbsClass) Commute() {} 69 | 70 | func (a AbsClass) Arrive() { 71 | fmt.Println("3. 到达") 72 | } 73 | 74 | type DriveToWork struct { 75 | AbsClass 76 | } 77 | 78 | 79 | func (d *DriveToWork) Commute() { 80 | fmt.Println("2. 开车去公司") 81 | } 82 | 83 | func (d *DriveToWork) GotoWork(work AbstractWork){ 84 | d.AbsClass.GotoWork(d) 85 | } 86 | 87 | type BusToWork struct { 88 | AbsClass 89 | } 90 | 91 | func (d *BusToWork) Commute() { 92 | fmt.Println("2. 坐公交去公司") 93 | } 94 | 95 | func (d *BusToWork) GotoWork(work AbstractWork) { 96 | d.AbsClass.GotoWork(d) 97 | } 98 | ``` 99 | 100 | 101 | 102 | ```go 103 | var ( 104 | work AbstractWork 105 | ) 106 | work = &BusToWork{AbsClass{}} 107 | work.GotoWork(work) 108 | work = &DriveToWork{AbsClass{}} 109 | work.GotoWork(work) 110 | ``` 111 | 112 | 113 | === RUN TestAbsClass_GotoWork 114 | 1. 起床 115 | 2. 坐公交去公司 116 | 3. 到达 117 | 1. 起床 118 | 2. 开车去公司 119 | 3. 到达 120 | --- PASS: TestAbsClass_GotoWork (0.00s) 121 | PASS 122 | 123 | 124 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Docs/策略模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 策略模式 4 | 5 | ### 定义 6 | 7 | >策略模式(Strategy Pattern: Define a family of algorithms,encapsulate each one,andmake them interchangeable.) 8 | 9 | 中文解释为:定义一组算法,然后将这些算法封装起来,以便它们之间可以互换,属于一种对象行为型模式。总的来说策略模式是一种比较简单的模式,听起来可能有点费劲,其实就是定义一组通用算法的上层接口,各个算法实现类实现该算法接口,封装模块使用类似于Context的概念,Context暴漏一组接口,Context内部接口委托到抽象算 10 | 法层。 11 | 12 | ### 类图 13 | 14 | ![](https://img.mukewang.com/5def3f3200014e3706030263.png) 15 | 16 | 包含的角色罗列如下: 17 | * 上下文角色(Context) :该角色一般是一个实现类或者封装类,起到一定的封装及隔离作用,实际接受请求并将请求委托给实际的算法实现类处理,避免外界对底层策略的直接访问; 18 | * 抽象策略角色( Strategy) :该角色一般是一一个抽象角色,为接口或者抽象类扮演,定义具体策略角色的公共接口; 19 | * 具体策略角色( ConcreteStrategy) :实现抽象策略角色的接口,为策略的具体实现类。 20 | 21 | 22 | ### 优缺点 23 | 策略模式的优点如下: 24 | 25 | * 所有策略放入一组抽象策略接口中,方便统一管理与实现; 26 | 策略模式的缺点如下: 27 | 28 | * 策略模式每种策略都是单独类,策略很多时策略实现类也很可观; 29 | * 客户端初始化Context的时候需要指定策略类,这样就要求客户端要熟悉各个策略,对调用方要求较高。 30 | 31 | ### 应用场景 32 | 33 | 策略模式的应用场景如下: 34 | * 需要自由切换算法的场景 35 | * 需要屏蔽算法实现细节的场景 36 | 37 | ### 使用实例:鸭子模型 38 | 39 | 类图: 40 | 41 | ![](http://www.liuanqihappybirthday.top/uploads/big/f8eaac871b522d737cf250ad67807aae.png) 42 | 43 | 44 | 45 | ```go 46 | import "fmt" 47 | 48 | type FlyBehavior interface { 49 | Fly() 50 | } 51 | 52 | type QuackBehavior interface { 53 | Quack() 54 | } 55 | 56 | type Duck struct { 57 | fly FlyBehavior 58 | quack QuackBehavior 59 | } 60 | 61 | func (d *Duck)Swim() { 62 | fmt.Println("鸭子游泳") 63 | } 64 | 65 | func (d *Duck) Display (behavior FlyBehavior,quackBehavior QuackBehavior) { 66 | behavior.Fly() 67 | quackBehavior.Quack() 68 | } 69 | 70 | type FlyWithWings struct {} 71 | 72 | func (f *FlyWithWings) Fly () { 73 | fmt.Println("鸭子用翅膀飞") 74 | } 75 | 76 | type FlyNoWay struct {} 77 | 78 | func (f *FlyNoWay) Fly () { 79 | fmt.Println("鸭子飞不起来") 80 | } 81 | 82 | type Quack struct {} 83 | 84 | func (f *Quack) Quack () { 85 | fmt.Println("鸭子嘎嘎叫") 86 | } 87 | 88 | type Squeak struct {} 89 | 90 | func (f *Squeak) Quack () { 91 | fmt.Println("鸭子咔咔叫") 92 | } 93 | 94 | type Mute struct {} 95 | 96 | func (f *Mute) Quack () { 97 | fmt.Println("鸭子不能叫") 98 | } 99 | 100 | type ReadHead struct { 101 | *Duck 102 | fly *FlyWithWings 103 | quack *Quack 104 | } 105 | 106 | func (r *ReadHead) Display () { 107 | r.Swim() 108 | r.Duck.Display(r.fly, r.quack) 109 | } 110 | 111 | type Wooden struct { 112 | *Duck 113 | fly *FlyNoWay 114 | quack *Mute 115 | } 116 | 117 | func (r *Wooden) Display () { 118 | r.Swim() 119 | r.Duck.Display(r.fly,r.quack) 120 | } 121 | 122 | type Mallard struct { 123 | *Duck 124 | fly *FlyWithWings 125 | quack *Quack 126 | } 127 | 128 | func (m *Mallard) Display () { 129 | m.Swim() 130 | m.Duck.Display(m.fly, m.quack) 131 | } 132 | 133 | type Rubber struct { 134 | *Duck 135 | fly *FlyNoWay 136 | quack *Squeak 137 | } 138 | 139 | func (r *Rubber) Display () { 140 | r.Swim() 141 | r.Duck.Display(r.fly, r.quack) 142 | } 143 | ``` 144 | 145 | 146 | ```go 147 | flynoway := &FlyNoWay{} 148 | flayWihtwings := &FlyWithWings{} 149 | quack := &Quack{} 150 | sqeak := &Squeak{} 151 | mute := &Mute{} 152 | duck := ReadHead{ 153 | Duck: &Duck{}, 154 | fly: flayWihtwings, 155 | quack: quack, 156 | } 157 | duck.Display() 158 | mallard := Mallard { 159 | Duck: &Duck{}, 160 | fly: flayWihtwings, 161 | quack: quack, 162 | } 163 | mallard.Display() 164 | rub := Rubber { 165 | Duck: &Duck{}, 166 | fly: flynoway, 167 | quack: sqeak, 168 | } 169 | rub.Display() 170 | wooden := Wooden{ 171 | Duck: &Duck{}, 172 | fly: flynoway, 173 | quack: mute, 174 | } 175 | wooden.Display() 176 | ``` 177 | 178 | 鸭子游泳 179 | 鸭子用翅膀飞 180 | 鸭子嘎嘎叫 181 | 鸭子游泳 182 | 鸭子用翅膀飞 183 | 鸭子嘎嘎叫 184 | 鸭子游泳 185 | 鸭子飞不起来 186 | 鸭子咔咔叫 187 | 鸭子游泳 188 | 鸭子飞不起来 189 | 鸭子不能叫 190 | 191 | 192 | ![](https://img.mukewang.com/5def3f210001f6e406300315.png) 193 | 194 | 195 | ```go 196 | 197 | ``` 198 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Docs/观察者模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 观察者模式 4 | 5 | ### 定义 6 | 7 | 观察者模式( Observer Pattern)也称发布阅模式。 8 | 9 | 观察者模式的英文定义如下: 10 | > Define a one-to-many dependency between objects so that when one objectchanges state, all its dependents are notified and updated automatically. 11 | 12 | 意思是:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。 13 | 14 | 以生活中的例子来说,就像我们订阅报纸一样,每天有多少人订阅,当有新报纸发布的时候,就会有多少人收到新发布的报纸,这种模式就是订阅一发布模式,而报社和订阅者就满足定义中说的,一对多的依赖关系。 15 | 16 | ### 类图 17 | 18 | 观察者模式包含如下角色: 19 | 20 | * 抽象主题(Subject) 角色:该角色又称为“发布者”或”被观察者,可以增加和删除观察者对象; 21 | 22 | * 具体主题( Concrete Subject) 角色:该角色又称为“具体发布者”或“具体被观察者”,它将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过(关联了观察关系)的观察者发出通知; 23 | 24 | * 抽象观察者(Observer) 角色:该角色又称为“订阅者”,定义一个接收通知的接口,在得到主题的通知时更新自己; 25 | 26 | * 具体观察者( Concrete Observer)角色:该角色又称为“ 具体订阅者”,它会实现-个接收通知的方法,用来使自身的状态与主题的状态相协调。 27 | 28 | ![](https://img.mukewang.com/5deef92c0001dfdf03740337.png) 29 | 30 | ### 优缺点 31 | 观察者模式的优点: 32 | * 观察者和被观察者之间,实现了抽象耦合。被观察者角色所知道的只是- 个具体观察者集合,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体的观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密的耦合在一起,因此它们可以属于不同的抽象化层次,且都非常容易扩展; 33 | 34 | * 此模式为广播模式,所有的观察者只需要订阅相应的主题,就能收到此主题下的所有广播。 35 | 36 | 观察者模式的缺点: 37 | 38 | * 观察者只知道被观察者会发生变化,但不知道何时会发生变化; 39 | * 如果主题之间有循环依赖,会导致系统崩溃,所以在使用时要特别注意此种情况; 40 | * 如果有很多个观察者,则每个通知会比较耗时。 41 | 42 | ### 应用场景 43 | 使用观察模式的典型应用场景如下: 44 | * 关联行为的场景,例如,在一个系统中,如果用户完善了个人资料,就会增加积分、添加日志、开放一些功能权限等,就比较适合用观察者模式; 45 | * 消息队列,例如,需要隔离发布者和订阅者,需要处理一对多关系的时候。 46 | ### 使用实例 47 | 以生活中的读者订阅为例,假设,读者A和读者B订阅了某平台的图书,当有新的图书发布时就会给两位读者发送图书,实现代码如下。 48 | 49 | 50 | ```go 51 | import "fmt" 52 | 53 | // 读者接口(订阅接口) 54 | type IReader interface { 55 | Update(bookName string) 56 | } 57 | 58 | // 读者类(订阅者) 59 | type Reader struct { 60 | name string 61 | } 62 | 63 | func (r *Reader) Update(bookName string) { 64 | fmt.Println(r.name,"-收到了图书",bookName) 65 | } 66 | 67 | // 平台接口(发布方接口) 68 | type IPlatform interface { 69 | Attach(reader IReader) 70 | Detach(reader IReader) 71 | NotifyObservers(bookName string) 72 | } 73 | 74 | // 具体发布类(发布方) 75 | type Platform struct { 76 | list []IReader 77 | } 78 | 79 | func (p *Platform) Attach(reader IReader) { 80 | // 增加读者(订阅者) 81 | p.list = append(p.list, reader) 82 | } 83 | 84 | func (p *Platform) Detach(reader IReader) { 85 | // 删除读者(订阅者) 86 | for i,v := range p.list { 87 | if v == reader { 88 | // 删除第i个元素,因为interface类型在golang中 89 | // 以地址的方式传递,所以可以直接比较进行删除 90 | // golang中只要记得byte,int,bool,string,数组,结构体,默认传值,其他的默认传地址即可 91 | p.list = append(p.list[:i],p.list[i+1:]...) 92 | } 93 | } 94 | } 95 | 96 | func (p *Platform) NotifyObservers(bookName string) { 97 | // 通知所有读者 98 | for _,reader := range p.list { 99 | reader.Update(bookName) 100 | } 101 | } 102 | 103 | func (p *Platform) Change (bookName string) { 104 | p.NotifyObservers(bookName) 105 | } 106 | 107 | 108 | ``` 109 | 110 | 111 | ```go 112 | // 创建图书平台(发布者) 113 | platform := Platform{list: []IReader{}} 114 | // 创建读者A 115 | reader := Reader{name:"A"} 116 | // 读者A订阅图书通知 117 | platform.Attach(&reader) 118 | // 创建读者B 119 | reader2 := Reader{name:"B"} 120 | // 读者B订阅图书通知 121 | platform.Attach(&reader2) 122 | platform.Change("《go核心编程》") 123 | // 读者B取消订阅 124 | platform.Detach(&reader2) 125 | platform.Change("《go高级编程》") 126 | ``` 127 | 128 | A -收到了图书 《go核心编程》 129 | B -收到了图书 《go核心编程》 130 | A -收到了图书 《go高级编程》 131 | 132 | 133 | 134 | ```go 135 | 136 | ``` 137 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Docs/解释器模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 解释器模式 4 | 5 | ### 定义 6 | 解释器模式( Interpreter Pattern )提供了评估语言的语法或者表达式的方式,属于一种行为型的设计模式。 7 | 解释器模式的英文原话是: 8 | > Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language. 9 | 10 | 意思是:给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。简单来说,就是我们可以定义一种语法比如就是一个表达式如: a-b+c, 起初我们并不知道这个句子想要携带信息或者执行什么操作,然后我们要定义一个解析器来进行表达式解析,以便得到正确的结果。 11 | 12 | 对于表达式: a-b+c 这种,我们做个简单的分析, a、b、c这种我们又叫做运算参数,+、-符号这种我们称之为运算符号,也就说这类表达式我们可以将其抽象为两种角色:运算参数、运算符号。运算参数一般就是英文字母,执行时各个参数需要赋上具体的数字值去替代英文字母执行,运算参数有一个共同点就是不管是a、b或者其它参数,除了被赋值之外不需要做其它任何处理,是执行时的最小单元,在解释器模式中被称为终结符号。运算符号是进行运算时具体要被解释器解释执行的部分,想象一下,加入我们计算机不知道如何处理类似+、-这种符号,我们是不要针对每一个符号写一个解释方法,以便告诉计算机该符号需要进行何种操作,这也就是解释器模式的核心——需要完成逻辑的解释执行操作,而运算符号在解释器模式中也被称为非终结符号。 13 | 14 | ### 类图 15 | 16 | ![](https://img.mukewang.com/5db7e8470001728903560198.png) 17 | 18 | 通常包含如下角色: 19 | * 抽象解释器( AbstractExpression) :抽象解释器是一个上层抽象类,用来抽取定义公共的解释方法: interpreter, 具体的解释任务交给子类去完成; . 20 | * 终结符表达式( TerminalExpression) :是抽象解释器的子类,实现了与文法中的元素相关的解释操作。一般模式中只会有一个终结符表达式也就是终结符的类,但是会有多个实例,比如: a、b、c,这些终结符号可以任意多种但是只有一个类来描述; 21 | * 非终结符表达式( NonTerminalExpression) :也是抽象解释器的子类,用来实现文法中与终结符相关的操作。该角色一般会有多个实现类,比如+、-运算符号就各自对应一种类实现,分别对应加法解释类和减法解释类,非终结符表达式的类的个数一般会有很多 ,因为我们可执行的操作一般会有很多,这也从侧面加剧了该模式下类设计的复杂性; 22 | * 上下文(Context) :上下文一般用来定义各个解释器需要的数据或公共功能,比如上面的表达式,我们使用上下文来保存各个参数的值,-般是- 个HashMap对象,以便后面所有解释器都可以使用该上下文来获取参数值; 23 | 24 | ### 优缺点 25 | 26 | 解释器模式的优点: 27 | * 拓展性强:修改文法规则只需要修改相应的非终结符表达式就可以了,即增加非终结符类就可以了。 28 | 解释器模式的缺点: 29 | * 采用递归调用方法,不利于调试,增加了系统的复杂性以及降低了系统执行的效率; 30 | * 解释器模式比较容易造成类设计的膨胀,主要是非终结符表达式类会随着系统的复杂性而膨胀; 31 | * 可利用的场景比较少; 32 | * 对于比较复杂的文法不好解析。 33 | ### 应用场景 34 | * 一个简单语法需要解释的场景,如: sql语法分析,用来解析那种比较标准的字符集; 35 | * 重复发生的问题可以使用解释器模式,如:日志分析,日志分析时基础数据是相同的类似于我们的终结符,但是日志格式往往是各异的,类似于非终结符,只需要指定具体的实现类即可。 36 | 37 | ### 使用实例 38 | 现在我们以一个最简单的例子: a+b,我们要做的就是解释执行这段语法文本,a和b是两个字母也叫做两个变量,我们需要使用一个“+”符号来将这俩变量连接起来,假设我们的语言并不知道符号"+"是什么作用,具体作用需要我们去实现(假设我们并不知道+其实是加法的意思),示例比较简单,只是为了说明解释器模式没别的意思。 39 | 40 | 41 | 42 | 43 | 44 | ```go 45 | import "bytes" 46 | 47 | type Context struct { 48 | text string 49 | } 50 | 51 | //抽象解释器 52 | type AbstractExpress interface { 53 | Interpreter(*Context) int 54 | } 55 | 56 | // 终结符,即我们的参数构造类 57 | type TerminalExpression struct { 58 | arg int 59 | } 60 | 61 | func (t *TerminalExpression) Interpreter(ctx *Context) int { 62 | return t.arg 63 | } 64 | 65 | // 非终结符,即我们的运算符构造类 66 | type NonTerminalExpression struct { 67 | left AbstractExpress 68 | right AbstractExpress 69 | } 70 | 71 | func (n NonTerminalExpression) Interpreter(ctx *Context) int { 72 | // 实现具体的a+b的解释执行操作 73 | if !bytes.Equal([]byte(ctx.text),[]byte("")) { 74 | return n.left.Interpreter(ctx) + n.right.Interpreter(ctx) 75 | } 76 | return 0 77 | } 78 | ``` 79 | 80 | 81 | ```go 82 | import "fmt" 83 | var ( 84 | left AbstractExpress 85 | right AbstractExpress 86 | callExpression AbstractExpress 87 | ) 88 | left = &TerminalExpression{arg:12} 89 | right = &TerminalExpression{arg:34} 90 | callExpression = &NonTerminalExpression{left:left,right:right} 91 | 92 | context := &Context{text:"+"} 93 | 94 | result := callExpression.Interpreter(context) 95 | fmt.Println(result) 96 | ``` 97 | 98 | 46 99 | 100 | ### 总结 101 | ![](https://img.mukewang.com/5db7e86100017d6006510281.png) 102 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Docs/迭代器模式.md: -------------------------------------------------------------------------------- 1 | 2 | ## 迭代器模式 3 | 4 | ### 定义 5 | 迭代器模式的英文定义如下: 6 | > Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. 7 | 8 | 意思是:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。迭代器是为容器服务的,容器是指用来容纳其他对象的对象,例如,Collection集合类型、Set类等。 9 | 10 | ### 类图 11 | 12 | ![](https://img.mukewang.com/5db7e8ef00012cfc06200286.png) 13 | 14 | 迭代器模式有以下4个角色: 15 | * 抽象迭代器(Iterator) 角色:该角色负责定义访问和遍历元素的接口; 16 | * 具体迭代器( Concrete Iterator) 角色:该角色实现Iterator接口,完成容器元素的遍历; 17 | * 抽象聚集(Aggregate) 角色:该角色提供创建迭代器角色的接口; 18 | * 具体聚集(Concrete Aggregate) 角色:该角色实现抽象聚集接口,创建出容纳迭代器的对象。 19 | 20 | ### 优缺点 21 | 迭代器模式的优点: 22 | * 迭代器模式将数据存储和数据遍历的职责进行分离; 23 | * 迭代器模式简化了遍历容器元素的操作; 24 | * 迭代器模式使不同的容器,具备一个统一的遍历接口; 25 | * 迭代器模式封装了遍历算法,使算法独立于聚集角色,调用者无须知道聚集对象的类型,即使聚集对象的类型发生变化,也不会影响遍历过程。 26 | 迭代器模式的缺点: 27 | * 由于迭代器模式将数据存储和数据遍历的职责进行分离,如果增加新的聚合类,同时需要增加与之相对,应的迭代器类,这使得类的个数会成对增加,在某种程度上来说增加了系统的复杂性。 28 | ### 应用场景 29 | 迭代器的应用很广泛,已经发展成为程序开发中最基础的工具类了。在Java语言中,从JDK1.2开始,增加了java.til.lterator 接口,并将Iterator 应用到各个聚集类( Collection)中,如ArrayList、 Vector、Stack、HashSet 等集合类都实现iterator() 方法,返回一个迭代器Iterator,用于对集合中的元素进行遍历。这使我们在项目中无须在独立地写迭代器,直接使用即可,这样既轻松又便捷。 30 | **注意:要尽可能地使用编程语言自身提供的迭代器,而非自己写的迭代器。** 31 | 32 | 33 | 34 | ```go 35 | // 抽象迭代器 36 | type Iterator interface { 37 | Next() interface{} 38 | HasNext() bool 39 | } 40 | 41 | // 具体迭代器 42 | type ConcreteIterator struct { 43 | index int 44 | size int 45 | con Aggregate 46 | } 47 | 48 | func (c *ConcreteIterator) HasNext() bool { 49 | return c.index < c.size 50 | } 51 | 52 | func (c *ConcreteIterator) Next() interface{} { 53 | if c.HasNext() { 54 | res := c.con.GetElement(c.index) 55 | c.index++ 56 | return res 57 | } 58 | return nil 59 | } 60 | 61 | 62 | 63 | // 抽象聚集 64 | type Aggregate interface { 65 | Add(obj interface{}) 66 | CreateIterator() Iterator 67 | GetElement(index int) interface{} 68 | Size() int 69 | } 70 | 71 | // 具体聚集 72 | type ConcreteAggregate struct { 73 | //私有存储容器 74 | docker []interface{} 75 | } 76 | 77 | func (c *ConcreteAggregate) Size() int { 78 | return len(c.docker) 79 | } 80 | 81 | func (c *ConcreteAggregate) Add(obj interface{}) { 82 | c.docker = append(c.docker,obj) 83 | } 84 | 85 | func (c *ConcreteAggregate) CreateIterator() Iterator { 86 | return &ConcreteIterator{ 87 | index: 0, 88 | size: c.Size(), 89 | con: c, 90 | } 91 | } 92 | 93 | func (c *ConcreteAggregate) GetElement(index int) interface{} { 94 | return c.docker[index] 95 | } 96 | 97 | 98 | ``` 99 | 100 | ```go 101 | // 定义聚族对象 102 | var ( 103 | aggregate Aggregate 104 | iter Iterator 105 | ) 106 | aggregate = &ConcreteAggregate{docker: []interface{}{}} 107 | aggregate.Add("java") 108 | aggregate.Add("Golang") 109 | aggregate.Add("Python") 110 | // 遍历 111 | iter = aggregate.CreateIterator() 112 | for iter.HasNext() { 113 | fmt.Println(iter.Next()) 114 | } 115 | ``` 116 | 117 | ``` 118 | === RUN TestConcreteAggregate_Add 119 | java 120 | Golang 121 | Python 122 | --- PASS: TestConcreteAggregate_Add (0.00s) 123 | PASS 124 | ``` -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Handler.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "fmt" 4 | 5 | const ( 6 | DIFFICULTY_LEVEL_1 = 1 7 | DIFFICULTY_LEVEL_2 = 2 8 | DIFFICULTY_LEVEL_3 = 3 9 | ) 10 | 11 | type HandleMessage func(hand Handler,request IRequest) 12 | 13 | 14 | type IRequest interface { 15 | // 请求级别 16 | GetRequestLevel() int 17 | // 获取要请求的内容 18 | GetRequest() string 19 | } 20 | 21 | type Request struct { 22 | // 难度1--初级工程师 23 | // 难度2--中级工程师 24 | // 难度3--高级工程师 25 | level int 26 | request string 27 | } 28 | 29 | func InitRequset(level int, request string) *Request { 30 | r := &Request{ 31 | level: level, 32 | request: request, 33 | } 34 | switch r.level { 35 | case 1: 36 | r.request = "难度级别1的请求是:"+ request 37 | case 2: 38 | r.request = "难度级别2的请求是:"+ request 39 | case 3: 40 | r.request = "难度级别3的请求是:"+ request 41 | } 42 | return r 43 | } 44 | 45 | func (r Request) GetRequestLevel() int { 46 | return r.level 47 | } 48 | 49 | func (r Request) GetRequest() string { 50 | return r.request 51 | } 52 | 53 | type Handler interface { 54 | HandleMessage(request IRequest,handler Handler,message HandleMessage) 55 | SetNextHandler(handler Handler) 56 | Response(request IRequest) 57 | GetLevel()int 58 | GetNext() Handler 59 | } 60 | 61 | // 初级工程师 62 | type Primary struct { 63 | level int 64 | request string 65 | next Handler 66 | } 67 | 68 | func (p *Primary) GetNext() Handler { 69 | return p.next 70 | } 71 | 72 | func (p *Primary) GetLevel() int { 73 | return p.level 74 | } 75 | 76 | func (p *Primary) HandleMessage(request IRequest,handler Handler,message HandleMessage) { 77 | message(p,request) 78 | } 79 | 80 | func (p *Primary) SetNextHandler(handler Handler) { 81 | p.next = handler 82 | } 83 | 84 | func (p *Primary) Response(request IRequest) { 85 | fmt.Println("---难度级别1的请求---") 86 | fmt.Printf(request.GetRequest()) 87 | fmt.Println("初级工程师已经处理完毕") 88 | } 89 | 90 | func InitPrimary() Handler { 91 | return &Primary{ 92 | level: DIFFICULTY_LEVEL_1, 93 | request: "", 94 | } 95 | } 96 | 97 | type Middle struct { 98 | level int 99 | request string 100 | next Handler 101 | } 102 | func HandleMess (hand Handler,request IRequest) { 103 | // 如果请求级别小于可以处理的级别就直接处理 104 | if request.GetRequestLevel() <= hand.GetLevel() { 105 | hand.Response(request) 106 | } else { 107 | if hand.GetNext() != nil { 108 | HandleMess(hand.GetNext(),request) 109 | } else { 110 | fmt.Println("---难度级别为",request.GetRequestLevel(),"的请求无法处理") 111 | } 112 | } 113 | } 114 | func (p *Middle) HandleMessage(request IRequest,handler Handler,message HandleMessage) { 115 | handler = p 116 | message(handler,request) 117 | } 118 | 119 | func (p *Middle) SetNextHandler(handler Handler) { 120 | p.next = handler 121 | } 122 | 123 | func (p *Middle) Response(request IRequest) { 124 | fmt.Println("---难度级别2的请求---") 125 | fmt.Printf(request.GetRequest()) 126 | fmt.Println("中级工程师已经处理完毕") 127 | } 128 | 129 | func (p *Middle) GetLevel() int { 130 | return p.level 131 | } 132 | 133 | func (p *Middle) GetNext() Handler { 134 | return p.next 135 | } 136 | 137 | type Senior struct { 138 | level int 139 | request string 140 | next Handler 141 | } 142 | 143 | func (p *Senior) HandleMessage(request IRequest,handler Handler,message HandleMessage) { 144 | handler = p 145 | message(handler,request) 146 | } 147 | 148 | func (p *Senior) SetNextHandler(handler Handler) { 149 | p.next = handler 150 | } 151 | 152 | func (p *Senior) Response(request IRequest) { 153 | fmt.Println("---难度级别3的请求---") 154 | fmt.Printf(request.GetRequest()) 155 | fmt.Println("高级工程师已经处理完毕") 156 | } 157 | 158 | func (p *Senior) GetLevel() int { 159 | return p.level 160 | } 161 | 162 | func (p *Senior) GetNext() Handler { 163 | return p.next 164 | } 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Handler_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "testing" 4 | 5 | func TestInitPrimary(t *testing.T) { 6 | var ( 7 | pri Handler 8 | mid Handler 9 | sen Handler 10 | list []IRequest 11 | ) 12 | list = make([]IRequest,0) 13 | list = append(list,&Request{ 14 | level: DIFFICULTY_LEVEL_1, 15 | request: "1+1=?", 16 | }) 17 | list = append(list,&Request{ 18 | level: DIFFICULTY_LEVEL_2, 19 | request: "4*3", 20 | }) 21 | list = append(list,&Request{ 22 | level: DIFFICULTY_LEVEL_3, 23 | request: "99*99", 24 | }) 25 | list = append(list,&Request{ 26 | level: 4, 27 | request: "aaaaaaaaaaa", 28 | }) 29 | pri = InitPrimary() 30 | mid = &Middle{ 31 | level: DIFFICULTY_LEVEL_2, 32 | request: "", 33 | next: nil, 34 | } 35 | sen = &Senior{ 36 | level: DIFFICULTY_LEVEL_3, 37 | request: "", 38 | next: nil, 39 | } 40 | 41 | // 设置链的顺序 42 | pri.SetNextHandler(mid) 43 | mid.SetNextHandler(sen) 44 | for _,v := range list { 45 | // 责任链中处理该请求 46 | pri.HandleMessage(v,pri,HandleMess) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Interpreter.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "bytes" 4 | 5 | type Context struct { 6 | text string 7 | } 8 | 9 | //抽象解释器 10 | type AbstractExpress interface { 11 | Interpreter(*Context) int 12 | } 13 | 14 | // 终结符,即我们的参数构造类 15 | type TerminalExpression struct { 16 | arg int 17 | } 18 | 19 | func (t *TerminalExpression) Interpreter(ctx *Context) int { 20 | return t.arg 21 | } 22 | 23 | // 非终结符,即我们的运算符构造类 24 | type NonTerminalExpression struct { 25 | left AbstractExpress 26 | right AbstractExpress 27 | } 28 | 29 | func (n NonTerminalExpression) Interpreter(ctx *Context) int { 30 | // 实现具体的a+b的解释执行操作 31 | if !bytes.Equal([]byte(ctx.text),[]byte("")) { 32 | return n.left.Interpreter(ctx) + n.right.Interpreter(ctx) 33 | } 34 | return 0 35 | } 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Interpreter_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "testing" 4 | 5 | //测试类 6 | func TestNonTerminalExpression_Interpreter(t *testing.T) { 7 | var ( 8 | left AbstractExpress 9 | right AbstractExpress 10 | callExpression AbstractExpress 11 | ) 12 | left = &TerminalExpression{arg:12} 13 | right = &TerminalExpression{arg:34} 14 | callExpression = &NonTerminalExpression{left:left,right:right} 15 | 16 | context := &Context{text:"+"} 17 | 18 | result := callExpression.Interpreter(context) 19 | t.Log(result) 20 | } 21 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Iterator.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | 4 | // 抽象迭代器 5 | type Iterator interface { 6 | Next() interface{} 7 | HasNext() bool 8 | } 9 | 10 | // 具体迭代器 11 | type ConcreteIterator struct { 12 | index int 13 | size int 14 | con Aggregate 15 | } 16 | 17 | func (c *ConcreteIterator) Next() interface{} { 18 | if c.HasNext() { 19 | res := c.con.GetElement(c.index) 20 | c.index++ 21 | return res 22 | } 23 | return nil 24 | } 25 | 26 | func (c *ConcreteIterator) HasNext() bool { 27 | return c.index < c.size 28 | } 29 | 30 | // 抽象聚集 31 | type Aggregate interface { 32 | Add(obj interface{}) 33 | CreateIterator() Iterator 34 | GetElement(index int) interface{} 35 | Size() int 36 | } 37 | 38 | // 具体聚集 39 | type ConcreteAggregate struct { 40 | //私有存储容器 41 | docker []interface{} 42 | } 43 | 44 | func (c *ConcreteAggregate) Add(obj interface{}) { 45 | c.docker = append(c.docker,obj) 46 | } 47 | 48 | func (c *ConcreteAggregate) CreateIterator() Iterator { 49 | return &ConcreteIterator{ 50 | index: 0, 51 | size: c.Size(), 52 | con: c, 53 | } 54 | } 55 | 56 | func (c *ConcreteAggregate) GetElement(index int) interface{} { 57 | return c.docker[index] 58 | } 59 | 60 | func (c *ConcreteAggregate) Size() int { 61 | return len(c.docker) 62 | } 63 | 64 | 65 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Iterator_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestConcreteAggregate_Add(t *testing.T) { 9 | // 定义聚族对象 10 | var ( 11 | aggregate Aggregate 12 | iter Iterator 13 | ) 14 | aggregate = &ConcreteAggregate{docker: []interface{}{}} 15 | aggregate.Add("java") 16 | aggregate.Add("Golang") 17 | aggregate.Add("Python") 18 | // 遍历 19 | iter = aggregate.CreateIterator() 20 | for iter.HasNext() { 21 | fmt.Println(iter.Next()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Mediator.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // 抽象中介公司 9 | type MeditorCompany interface { 10 | GetSeller() Colleaguer 11 | SetSeller(seller ColleagueSeller) 12 | GetBuyer() Colleaguer 13 | SetBuyer(ColleagueBuyer) 14 | GetName() string 15 | SetName(name string) 16 | Publish(message string,colleaguer Colleaguer) 17 | 18 | } 19 | // 具体中介者 20 | type Meditor struct { 21 | name string 22 | buyer *ColleagueBuyer 23 | seller *ColleagueSeller 24 | } 25 | 26 | func (m *Meditor) SetSeller(seller ColleagueSeller) { 27 | m.seller = &seller 28 | } 29 | 30 | func (m *Meditor) SetBuyer(b ColleagueBuyer) { 31 | m.buyer = &b 32 | } 33 | 34 | func (m *Meditor) Publish(message string, colleaguer Colleaguer) { 35 | // 如果是卖家发布 36 | if reflect.DeepEqual(colleaguer,m.seller){ 37 | m.buyer.Accept(message) 38 | } else if reflect.DeepEqual(colleaguer, m.buyer) { 39 | m.seller.Accept(message) 40 | } 41 | } 42 | 43 | func (m *Meditor) GetSeller() Colleaguer { 44 | return m.seller 45 | } 46 | 47 | func (m *Meditor) GetBuyer() Colleaguer { 48 | return m.buyer 49 | } 50 | 51 | func (m *Meditor) GetName() string { 52 | return m.name 53 | } 54 | 55 | func (m *Meditor) SetName(name string) { 56 | m.name = name 57 | } 58 | 59 | // 抽象同事角色 60 | type Colleaguer interface { 61 | Colleguer(meditor MeditorCompany) 62 | Send(string) 63 | Accept(string) 64 | } 65 | 66 | // 卖家-同事角色 67 | type ColleagueSeller struct { 68 | meditor MeditorCompany 69 | } 70 | 71 | func (c *ColleagueSeller) Send(message string) { 72 | c.meditor.Publish(message,c) 73 | } 74 | 75 | func (c *ColleagueSeller) Accept(message string) { 76 | fmt.Println("卖家收到的消息是"+message) 77 | } 78 | 79 | func (c *ColleagueSeller) Colleguer(meditor MeditorCompany) { 80 | c.meditor = meditor 81 | } 82 | 83 | // 买家-同事角色 84 | 85 | type ColleagueBuyer struct { 86 | meditor MeditorCompany 87 | } 88 | 89 | func (c *ColleagueBuyer) Colleguer(meditor MeditorCompany) { 90 | c.meditor = meditor 91 | } 92 | 93 | func (c *ColleagueBuyer) Send(message string) { 94 | c.meditor.Publish(message,c) 95 | } 96 | 97 | func (c *ColleagueBuyer) Accept(message string) { 98 | fmt.Println("买家收到的消息是"+message) 99 | } 100 | 101 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Mediator_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "testing" 4 | 5 | func TestColleagueSeller_Colleguer(t *testing.T) { 6 | var ( 7 | meitdor MeditorCompany 8 | seller *ColleagueSeller 9 | buyer *ColleagueBuyer 10 | ) 11 | seller = &ColleagueSeller{meditor:meitdor} 12 | buyer = &ColleagueBuyer{meditor:meitdor} 13 | meitdor = &Meditor{ 14 | name: "58同城", 15 | buyer: buyer, 16 | seller: seller, 17 | } 18 | // 卖家和卖家注册到中介 19 | seller.Colleguer(meitdor) 20 | buyer.Colleguer(meitdor) 21 | // 发布需求 22 | seller.Send("卖一套两室一厅100平米的Lofty") 23 | buyer.Send("求购一个两室一厅的房子") 24 | } 25 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Memento.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | // 备忘录 4 | type Memento struct { 5 | state string // 这里就是保存的状态 6 | } 7 | 8 | func (m *Memento) SetState(s string) { 9 | m.state = s 10 | } 11 | 12 | func (m *Memento) GetState() string { 13 | return m.state 14 | } 15 | 16 | // 发起人 17 | type Originator struct { 18 | state string // 这里就简单一点,要保存的状态就是一个字符串 19 | } 20 | 21 | func (o *Originator) SetState(s string) { 22 | o.state = s 23 | } 24 | 25 | func (o *Originator) GetState() string { 26 | return o.state 27 | } 28 | 29 | // 这里就是规定了要保存的状态范围 30 | func (o *Originator) CreateMemento() *Memento { 31 | return &Memento{state: o.state} 32 | } 33 | 34 | // 负责人 35 | type Caretaker struct { 36 | memento *Memento 37 | } 38 | 39 | func (c *Caretaker) GetMemento() *Memento { 40 | return c.memento 41 | } 42 | 43 | func (c *Caretaker) SetMemento(m *Memento) { 44 | c.memento = m 45 | } -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Memento_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestCaretaker_GetMemento(t *testing.T) { 9 | // 创建一个发起人并设置初始状态 10 | // 此时与备忘录模式无关,只是模拟正常程序运行 11 | o := &Originator{state: "hello"} 12 | fmt.Println("当前状态:",o.GetState()) 13 | // 现在需要保存当前状态 14 | // 就创建一个负责人来设置(一般来说,对于一个对象的同一个备忘范围,应当只有一个负责人,这样方便做多状态多备忘管理) 15 | c := new(Caretaker) 16 | c.SetMemento(o.CreateMemento()) 17 | 18 | o.SetState("world") 19 | fmt.Println("更改当前状态:",o.GetState()) 20 | 21 | // 恢复备忘 22 | o.SetState(c.GetMemento().GetState()) 23 | fmt.Println("恢复后状态",o.GetState()) 24 | } 25 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Observer.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "fmt" 4 | 5 | // 发布订阅,观察者模式 6 | //意思是:定义对象间一种一-对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对 7 | //象都会得到通知并被自动更新。 8 | //以生活中的例子来说,就像我们订阅报纸一样,每天有多少人订阅,当有新报纸发布的时候,就 9 | //会有多少人收到新发布的报纸,这种模式就是订阅一发布模式,而报社和订阅者就满足定义中 10 | //说是的,-对多的依赖关系。 11 | 12 | // 读者接口(订阅接口) 13 | type IReader interface { 14 | Update(bookName string) 15 | } 16 | 17 | // 读者类(订阅者) 18 | type Reader struct { 19 | name string 20 | } 21 | 22 | func (r *Reader) Update(bookName string) { 23 | fmt.Println(r.name,"-收到了图书",bookName) 24 | } 25 | 26 | // 平台接口(发布方接口) 27 | type IPlatform interface { 28 | Attach(reader IReader) 29 | Detach(reader IReader) 30 | NotifyObservers(bookName string) 31 | } 32 | 33 | // 具体发布类(发布方) 34 | type Platform struct { 35 | list []IReader 36 | } 37 | 38 | func (p *Platform) Attach(reader IReader) { 39 | // 增加读者(订阅者) 40 | p.list = append(p.list, reader) 41 | } 42 | 43 | func (p *Platform) Detach(reader IReader) { 44 | // 删除读者(订阅者) 45 | for i,v := range p.list { 46 | if v == reader { 47 | // 删除第i个元素,因为interface类型在golang中 48 | // 以地址的方式传递,所以可以直接比较进行删除 49 | // golang中只要记得byte,int,bool,string,数组,结构体,默认传值,其他的默认传地址即可 50 | p.list = append(p.list[:i],p.list[i+1:]...) 51 | } 52 | } 53 | } 54 | 55 | func (p *Platform) NotifyObservers(bookName string) { 56 | // 通知所有读者 57 | for _,reader := range p.list { 58 | reader.Update(bookName) 59 | } 60 | } 61 | 62 | func (p *Platform) Change (bookName string) { 63 | p.NotifyObservers(bookName) 64 | } 65 | 66 | 67 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Observer_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "testing" 4 | 5 | func TestPlatform_Attach(t *testing.T) { 6 | // 创建图书平台(发布者) 7 | platform := Platform{list: []IReader{}} 8 | // 创建读者A 9 | reader := Reader{name:"A"} 10 | // 读者A订阅图书通知 11 | platform.Attach(&reader) 12 | // 创建读者B 13 | reader2 := Reader{name:"B"} 14 | // 读者B订阅图书通知 15 | platform.Attach(&reader2) 16 | platform.Change("《go核心编程》") 17 | // 读者B取消订阅 18 | platform.Detach(&reader2) 19 | platform.Change("《go高级编程》") 20 | } 21 | 22 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/State.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "fmt" 4 | 5 | type TVState interface { 6 | // 开机 7 | PowerOn(r *RemoteControlMachine) 8 | // 关机 9 | PowerOff(r *RemoteControlMachine) 10 | // 播放 11 | Play(r *RemoteControlMachine) 12 | // 待机 13 | Standby(r *RemoteControlMachine) 14 | } 15 | // 待机状态 16 | type StandByState struct { 17 | r *RemoteControlMachine 18 | } 19 | 20 | func (s *StandByState) PowerOn(r *RemoteControlMachine) {} 21 | 22 | func (s *StandByState) PowerOff(r *RemoteControlMachine) { 23 | fmt.Println("关机") 24 | // 使用遥控器设置电视机状态为关机 25 | s.r = r 26 | s.r.SetCurrentSate(&PowerOffState{}) 27 | // 执行关机 28 | s.r.PowerOff() 29 | } 30 | 31 | func (s *StandByState) Play(r *RemoteControlMachine) { 32 | fmt.Println("播放") 33 | // 使用遥控器设置电视机状态为播放 34 | s.r = r 35 | s.r.SetCurrentSate(&PlayState{}) 36 | // 执行播放 37 | s.r.Play() 38 | } 39 | 40 | func (s *StandByState) Standby(r *RemoteControlMachine) { 41 | // do nothing 42 | } 43 | // 关机状态 44 | type PowerOffState struct { 45 | r *RemoteControlMachine 46 | } 47 | 48 | func (s *PowerOffState) PowerOn(r *RemoteControlMachine) { 49 | fmt.Println("开机") 50 | // 使用遥控器设置电视机状态为开机 51 | s.r = r 52 | s.r.SetCurrentSate(&StandByState{}) 53 | // 执行播放 54 | s.r.Standby() 55 | } 56 | 57 | func (s *PowerOffState) PowerOff(r *RemoteControlMachine) { 58 | } 59 | 60 | func (s *PowerOffState) Play(r *RemoteControlMachine) { 61 | } 62 | 63 | func (s PowerOffState) Standby(r *RemoteControlMachine) { 64 | } 65 | 66 | // 播放状态 67 | type PlayState struct { 68 | r *RemoteControlMachine 69 | } 70 | 71 | func (s *PlayState) PowerOn(r *RemoteControlMachine) {} 72 | 73 | func (s *PlayState) PowerOff(r *RemoteControlMachine) { 74 | fmt.Println("关机") 75 | // 使用遥控器设置电视机状态为关机 76 | s.r = r 77 | s.r.SetCurrentSate(&PowerOffState{}) 78 | // 执行关机 79 | s.r.PowerOff() 80 | } 81 | 82 | func (s *PlayState) Play(r *RemoteControlMachine) { 83 | } 84 | 85 | func (s *PlayState) Standby(r *RemoteControlMachine) { 86 | fmt.Println("开机") 87 | // 使用遥控器设置电视机状态为开机 88 | s.r = r 89 | s.r.SetCurrentSate(&StandByState{}) 90 | // 执行播放 91 | s.r.Standby() 92 | } 93 | 94 | // 引入控制器(上下文角色) 95 | type RemoteControlMachine struct { 96 | currentSate TVState 97 | } 98 | 99 | func (r *RemoteControlMachine) PowerOn() { 100 | r.currentSate.PowerOn(r) 101 | } 102 | 103 | func (r *RemoteControlMachine) PowerOff() { 104 | r.currentSate.PowerOff(r) 105 | } 106 | 107 | func (r *RemoteControlMachine) Play() { 108 | r.currentSate.Play(r) 109 | } 110 | 111 | func (r *RemoteControlMachine) Standby() { 112 | r.currentSate.Standby(r) 113 | } 114 | 115 | func (r *RemoteControlMachine) CurrentSate() TVState { 116 | return r.currentSate 117 | } 118 | 119 | func (r *RemoteControlMachine) SetCurrentSate(currentSate TVState) { 120 | r.currentSate = currentSate 121 | } 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/State_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "testing" 4 | 5 | func TestTelev_Play(t *testing.T) { 6 | context := RemoteControlMachine{} 7 | 8 | context.SetCurrentSate(&PowerOffState{}) 9 | // 如果直接播放,因为电视处于关机状态,所以不会有输出 10 | context.Play() 11 | 12 | context.PowerOn() 13 | context.Play() 14 | context.Standby() 15 | context.PowerOff() 16 | } 17 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Strategy.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "fmt" 4 | 5 | type FlyBehavior interface { 6 | Fly() 7 | } 8 | 9 | type QuackBehavior interface { 10 | Quack() 11 | } 12 | 13 | type Duck struct { 14 | fly FlyBehavior 15 | quack QuackBehavior 16 | } 17 | 18 | func (d *Duck)Swim() { 19 | fmt.Println("鸭子游泳") 20 | } 21 | 22 | func (d *Duck) Display (behavior FlyBehavior,quackBehavior QuackBehavior) { 23 | behavior.Fly() 24 | quackBehavior.Quack() 25 | } 26 | 27 | type FlyWithWings struct {} 28 | 29 | func (f *FlyWithWings) Fly () { 30 | fmt.Println("鸭子用翅膀飞") 31 | } 32 | 33 | type FlyNoWay struct {} 34 | 35 | func (f *FlyNoWay) Fly () { 36 | fmt.Println("鸭子飞不起来") 37 | } 38 | 39 | type Quack struct {} 40 | 41 | func (f *Quack) Quack () { 42 | fmt.Println("鸭子嘎嘎叫") 43 | } 44 | 45 | type Squeak struct {} 46 | 47 | func (f *Squeak) Quack () { 48 | fmt.Println("鸭子咔咔叫") 49 | } 50 | 51 | type Mute struct {} 52 | 53 | func (f *Mute) Quack () { 54 | fmt.Println("鸭子不能叫") 55 | } 56 | 57 | type ReadHead struct { 58 | *Duck 59 | fly *FlyWithWings 60 | quack *Quack 61 | } 62 | 63 | func (r *ReadHead) Display () { 64 | r.Swim() 65 | r.Duck.Display(r.fly, r.quack) 66 | } 67 | 68 | type Wooden struct { 69 | *Duck 70 | fly *FlyNoWay 71 | quack *Mute 72 | } 73 | 74 | func (r *Wooden) Display () { 75 | r.Swim() 76 | r.Duck.Display(r.fly,r.quack) 77 | } 78 | 79 | type Mallard struct { 80 | *Duck 81 | fly *FlyWithWings 82 | quack *Quack 83 | } 84 | 85 | func (m *Mallard) Display () { 86 | m.Swim() 87 | m.Duck.Display(m.fly, m.quack) 88 | } 89 | 90 | type Rubber struct { 91 | *Duck 92 | fly *FlyNoWay 93 | quack *Squeak 94 | } 95 | 96 | func (r *Rubber) Display () { 97 | r.Swim() 98 | r.Duck.Display(r.fly, r.quack) 99 | } -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Strategy_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "testing" 4 | 5 | func TestReadHead_Display(t *testing.T) { 6 | flynoway := &FlyNoWay{} 7 | flayWihtwings := &FlyWithWings{} 8 | quack := &Quack{} 9 | sqeak := &Squeak{} 10 | mute := &Mute{} 11 | duck := ReadHead{ 12 | Duck: &Duck{}, 13 | fly: flayWihtwings, 14 | quack: quack, 15 | } 16 | duck.Display() 17 | mallard := Mallard { 18 | Duck: &Duck{}, 19 | fly: flayWihtwings, 20 | quack: quack, 21 | } 22 | mallard.Display() 23 | rub := Rubber { 24 | Duck: &Duck{}, 25 | fly: flynoway, 26 | quack: sqeak, 27 | } 28 | rub.Display() 29 | wooden := Wooden{ 30 | Duck: &Duck{}, 31 | fly: flynoway, 32 | quack: mute, 33 | } 34 | wooden.Display() 35 | } -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Template.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "fmt" 4 | 5 | // 意思是:定义一个操作中的算法的框架,而将一些步骤延迟到子类中。 使得子类可以不改变-一个 6 | //算法的结构即可重定义该算法的某些特定步骤。 7 | //简单来说,就是为子类设计一个模板,以便在子类中可以复用这些方法。 8 | 9 | // 以生活中.上班的过程为例,我们上班的通常流程是:起床洗漱->通勤(开车、坐公交、打车) 10 | //->到达公司。从以上步骤可以看出,只有通勤部分是不一样的,其他都一样,因为开车可能会 11 | //被限号,就只能打车或坐公交去公司了,下面我们用代码( 模板模式)来实现一下。 12 | 13 | 14 | // 上班抽象模板接口 15 | type AbstractWork interface { 16 | GotoWork(work AbstractWork) 17 | Getup() 18 | Commute() 19 | Arrive() 20 | } 21 | 22 | type AbsClass struct {} 23 | 24 | func (a AbsClass) GotoWork(work AbstractWork) { 25 | a.Getup() 26 | work.Commute() 27 | a.Arrive() 28 | } 29 | 30 | func (a AbsClass) Getup() { 31 | fmt.Println("1. 起床") 32 | } 33 | 34 | func (a AbsClass) Commute() {} 35 | 36 | func (a AbsClass) Arrive() { 37 | fmt.Println("3. 到达") 38 | } 39 | 40 | type DriveToWork struct { 41 | AbsClass 42 | } 43 | 44 | 45 | func (d *DriveToWork) Commute() { 46 | fmt.Println("2. 开车去公司") 47 | } 48 | 49 | func (d *DriveToWork) GotoWork(work AbstractWork){ 50 | d.AbsClass.GotoWork(d) 51 | } 52 | 53 | type BusToWork struct { 54 | AbsClass 55 | } 56 | 57 | func (d *BusToWork) Commute() { 58 | fmt.Println("2. 坐公交去公司") 59 | } 60 | 61 | func (d *BusToWork) GotoWork(work AbstractWork) { 62 | d.AbsClass.GotoWork(d) 63 | } 64 | 65 | -------------------------------------------------------------------------------- /DesignPatterns/BehavioralType/Template_test.go: -------------------------------------------------------------------------------- 1 | package BehavioralType 2 | 3 | import "testing" 4 | 5 | func TestAbsClass_GotoWork(t *testing.T) { 6 | var ( 7 | work AbstractWork 8 | ) 9 | work = &BusToWork{AbsClass{}} 10 | work.GotoWork(work) 11 | work = &DriveToWork{AbsClass{}} 12 | work.GotoWork(work) 13 | 14 | } 15 | -------------------------------------------------------------------------------- /DesignPatterns/Compound_test.go: -------------------------------------------------------------------------------- 1 | package DesignPatterns 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // 复合模式测试代码 8 | func TestDuckCall_RemoveObserver(t *testing.T) { 9 | var ( 10 | factory AbsDuckFactory 11 | quackable QuackAble 12 | creak Creak 13 | flok *Flock 14 | observer Observer 15 | ) 16 | t.Log("测试抽象工厂") 17 | factory = &DuckFactory{} 18 | quackable = factory.CreateMallardDuck() 19 | quackable.quack() 20 | quackable = factory.CreateRedheadDuck() 21 | quackable.quack() 22 | quackable = factory.CreateDuckCall() 23 | quackable.quack() 24 | quackable = factory.CreateRubber() 25 | quackable.quack() 26 | t.Log("测试适配器") 27 | creak = &Goose{} 28 | adapter := &GooseAdapter{creak} 29 | adapter.quack() 30 | t.Log("测试组合模式") 31 | flok = &Flock{qs: []QuackAble{}} 32 | flok.Add(quackable) 33 | flok.quack() 34 | t.Log("测试观察者模式") 35 | observer = &DuckDoctor{} 36 | 37 | quackable.RegisterObserver(observer) 38 | //quackable.NotifyObservers() 39 | flok.NotifyObservers() 40 | quackable = factory.CreateRedheadDuck() 41 | quackable.RegisterObserver(observer) 42 | //quackable.NotifyObservers() 43 | flok.Add(quackable) 44 | flok.NotifyObservers() 45 | } 46 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/AbstractFactory.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | import "fmt" 4 | 5 | type Factory interface { 6 | NewTV() Television 7 | NewRefrigerator() Refrigerator 8 | } 9 | 10 | type Television interface { 11 | DoSomething() 12 | } 13 | 14 | type Refrigerator interface { 15 | DoSomething() 16 | } 17 | 18 | type TCLTV struct { 19 | } 20 | 21 | func (TCLTV) DoSomething () { 22 | fmt.Println("TCL电视在Do Something") 23 | } 24 | 25 | type TCLRef struct { 26 | } 27 | 28 | func (TCLRef) DoSomething () { 29 | fmt.Println("TCL空调在do something") 30 | } 31 | 32 | type MediaTV struct { 33 | } 34 | 35 | func (MediaTV)DoSomething() { 36 | fmt.Println("美的电视在do something") 37 | } 38 | 39 | type MediaRef struct{} 40 | 41 | func (MediaRef)DoSomething() { 42 | fmt.Println("美的空调在do something") 43 | } 44 | 45 | type TCLFactory struct { 46 | } 47 | 48 | func (TCLFactory) NewTV () Television { 49 | return TCLTV{} 50 | } 51 | 52 | func (TCLFactory)NewRefrigerator () Refrigerator { 53 | return TCLRef{} 54 | } 55 | 56 | type MediaFactory struct { 57 | } 58 | 59 | func (MediaFactory) NewTV () Television { 60 | return MediaTV{} 61 | } 62 | 63 | func (MediaFactory)NewRefrigerator () Refrigerator { 64 | return MediaRef{} 65 | } 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/Builder.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | import "fmt" 4 | 5 | //所谓万丈高楼平地起,但是我们建造(Build) 高楼时,需要经历很多阶段,比如打地基、搭框 6 | //架、浇筑水泥、封顶等,这些都是很难一气呵成的。 所以一般我们是先建造组成高楼的各个部 7 | //分,然后将其-个个地组装起来,好比搭积木一般,分阶段拼接后组装成一个完整的物体。 还有 8 | //个问题,就是同样的积木,同样的搭建过程,却能Build出不同的物体,这就叫做建造者模 9 | //式。 10 | //将一个复杂的对象的构建与它的表示相分离,使得同样的构建过程可以创建出不同的表示。建造 11 | //者模式(Builder Pattern)也叫做生成器模式。 12 | 13 | 14 | //建造者模式通常有以下几部分角色组成: 15 | //●建造者(Builder) : Builder 角色负责定义用来生成实例的接口(API) ; 16 | //●具体的建造者(ConcreateBuilder) : ConcreateBuilder角色负责实现Builder角色定义 17 | //的接口的实现类。针对不同的商业逻辑,具体化复杂对象的各部分的创建。在建造完成之后 18 | //提供产品的实例; 19 | //●监工(Director) : Director角色负责使用Builder角色的接口API来生成实例。内部不涉 20 | //及具体产品信息,只负责保证对象各部分完整创建或按照某种顺序进行创建。即Director是 21 | //负责指挥如何build的,只负责调度,具体实施交给具体的建造者; 22 | //●产品(Product) :即要创建的复杂对象; 23 | //●使用者(Client) :实际使用Builder模式的角色,即下面的测试类。 24 | 25 | type Product struct { 26 | ground string 27 | cement string 28 | roof string 29 | } 30 | 31 | func (p *Product) Cement() string { 32 | return p.cement 33 | } 34 | 35 | func (p *Product) SetCement(cement string) { 36 | p.cement = cement 37 | } 38 | 39 | func (p *Product) Roof() string { 40 | return p.roof 41 | } 42 | 43 | func (p *Product) SetRoof(roof string) { 44 | p.roof = roof 45 | } 46 | 47 | func (p *Product) Ground() string { 48 | return p.ground 49 | } 50 | 51 | func (p *Product) SetGround(ground string) { 52 | p.ground = ground 53 | } 54 | 55 | type Builder interface { 56 | BuildGround() 57 | BuildCement() 58 | BuildRoof() 59 | BuildProduct() *Product 60 | } 61 | 62 | type ConcreteBuilder struct { 63 | p *Product 64 | } 65 | 66 | func (this *ConcreteBuilder) BuildGround() { 67 | this.p.SetGround("建造地基") 68 | fmt.Println(this.p.ground) 69 | } 70 | 71 | func (this *ConcreteBuilder) BuildCement() { 72 | this.p.SetCement("建造房子") 73 | fmt.Println(this.p.Cement()) 74 | } 75 | func (this *ConcreteBuilder) BuildRoof() { 76 | this.p.SetRoof("建造房顶") 77 | fmt.Println(this.p.Roof()) 78 | } 79 | 80 | func (this *ConcreteBuilder) BuildProduct() *Product { 81 | fmt.Println("建造完毕") 82 | return this.p 83 | } 84 | 85 | type Director struct { 86 | builder Builder 87 | } 88 | 89 | func (this *Director) Construst() Product { 90 | this.builder.BuildGround() 91 | this.builder.BuildCement() 92 | this.builder.BuildRoof() 93 | 94 | return *this.builder.BuildProduct() 95 | } 96 | // 优缺点 97 | //●封装性:客户端不必知道产品内部组合细节,只需关心我们要生成某个对象,具体对象产生 98 | //细节不必知晓。Main 类并不知道Builder类,它只是调用了Director类的construct方法 99 | //完成对象的获取; 100 | //●建造者独立,易于拓展:上面我们只列举了ConcreteBuilder建造者类,如果需要其它建造 101 | //者新建类即可。建造者之间彼此独立,系统拓展性好,符合开闭原则; 102 | //●便于控制细节风险:由于具体建造者是独立的,因此可以对具体建造过程逐步细化,不会对 103 | //其它模块产生影响。 104 | 105 | 106 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/Docs/原型模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## 原型模式 5 | 6 | 原型模式不单是一种设计模式,也是一种编程范型。 简单理解原型模式Prototype:不根据类来生成实例,而是根据实例生成新的实例。也就说,如果需要一个和某个对象一模一样的对象,那么就可以使用原型模式。 7 | 8 | ### 定义 9 | 10 | 从设计模式的角度讲,原型模式是一种创建型模式, 摆脱了类的构造模式,原型模式告诉我们,想要创建一个对象, 我们不必关心对象的具体类型,而是找到一个对象,然后通过克隆来创建一个一模一样的对象。 11 | 12 | ### 类图 13 | 14 | ![原型模式](http://www.liuanqihappybirthday.top/uploads/big/668597d2a342e7f68caf0ca133992114.jpg) 15 | 16 | ### 扩展阅读: 深拷贝与浅拷贝 17 | 18 | `go` 语言中的传递都是值传递,传递一个对象,就会把对象拷贝一份传入函数中,传递一个指针,就会把指针拷贝一份传入进去。 19 | 20 | 赋值的时候也是这样,`res:=*e` 就会把传递的 `Example` 对象拷贝一份,如果是 `res:=e` 的话,那么拷贝的就是对象的指针了. 21 | 22 | 而深拷贝和浅拷贝也可以这样理解,深拷贝就是拷贝整个对象,浅拷贝就是拷贝对象指针。 23 | 24 | 对于深度拷贝,`go`和其他语言还经常使用序列化后反序列化的形式进行拷贝: 25 | 26 | ```go 27 | func deepCopy(dst, src interface{}) error { 28 | var buf bytes.Buffer 29 | if err := gob.NewEncoder(&buf).Encode(src); err != nil { 30 | return err 31 | } 32 | return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst) 33 | } 34 | ``` 35 | 36 | 实际上`gob`包序列化的时候也是用到了 `reflect`包来实现拷贝的 37 | 38 | **注意:** golang完全是按值传递,所以如果深度拷贝的对象中包含有指针的话,那么深度拷贝后,这些指针也会相同,会导致部分数据共享,要注意这一点. 39 | 40 | ### 总结 41 | 42 | ![](https://img.mukewang.com/5db11db8000175f805570171.png) 43 | 44 | 45 | ```go 46 | // 设计一个类的时候,我们通常会使用到构造函数,这里类和对象的关系好比模具和构件的关系, 47 | // 对象总是从类中创建的。但是某些场景下是不允许类的调用者直接调用构造函数,也就说对象未 48 | // 必需要从类中衍生出来,现实生活中存在太多案例是通过直接“克隆” 来产生新的对象,而且 49 | // 克隆出来的本体和克隆体看不出任何区别。 50 | // 原型模式不单是一种设计模式,也是一种编程范型。 简单理解原型模式Prototype:不根据类 51 | // 来生成实例,而是根据实例生成新的实例。也就说,如果需要一个和某对象一 模一样的对象,那 52 | // 么就可以使用原型模式。 53 | import "fmt" 54 | 55 | 56 | ``` 57 | 58 | 59 | ```go 60 | type Role interface { 61 | SetHeadColor(string) 62 | SetEyesColor(string) 63 | SetTall(int64) 64 | Show() 65 | Clone() Role 66 | } 67 | ``` 68 | 69 | 70 | interface method 0 is not a function: xreflect.Forward 71 | 72 | 73 | 74 | ```go 75 | type RoleChinese struct { 76 | HeadColor string 77 | EyesColor string 78 | Tall int64 79 | } 80 | 81 | func (pR *RoleChinese) Clone() Role { 82 | var pChinese = &RoleChinese{HeadColor: pR.HeadColor, EyesColor: pR.EyesColor, Tall: pR.Tall} 83 | return pChinese 84 | } 85 | 86 | func (pR *RoleChinese) SetHeadColor(color string) { 87 | pR.HeadColor = color 88 | } 89 | 90 | func (pR *RoleChinese) SetEyesColor(color string) { 91 | pR.EyesColor = color 92 | } 93 | 94 | func (pR *RoleChinese) SetTall(tall int64) { 95 | pR.Tall = tall 96 | } 97 | 98 | func (pR *RoleChinese) Show() { 99 | fmt.Println("Role's headcolor is:", pR.HeadColor, " EyesColor is:", pR.EyesColor, " tall is:", pR.Tall) 100 | } 101 | ``` 102 | 103 | 104 | ```go 105 | role := &RoleChinese{ 106 | HeadColor: "black", 107 | EyesColor: "black", 108 | Tall: 170, 109 | } 110 | role.Show() 111 | copyer := role.Clone() 112 | copyer.Show() 113 | copyer.SetEyesColor("bule") 114 | role.Show() 115 | copyer.Show() 116 | ``` 117 | 118 | 119 | ```go 120 | === RUN TestRoleChinese_Clone 121 | Role's headcolor is: black EyesColor is: black tall is: 170 122 | Role's headcolor is: black EyesColor is: black tall is: 170 123 | Role's headcolor is: black EyesColor is: black tall is: 170 124 | Role's headcolor is: black EyesColor is: bule tall is: 170 125 | --- PASS: TestRoleChinese_Clone (0.00s) 126 | PASS 127 | ``` 128 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/Docs/建造者模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## 建造者模式 5 | 6 | **将一个复杂的对象的构建与它的表示相分离,使得同样的构建过程可以创建出不同的表示。建造者模式(Builder Pattern)也叫做生成器模式。** 7 | 8 | ### 组成角色 9 | 10 | 建造者模式通常有以下几部分角色组成: 11 | 12 | ●建造者(Builder) : Builder 角色负责定义用来生成实例的接口(API) ; 13 | 14 | ●具体的建造者(ConcreateBuilder) : ConcreateBuilder 角色是负责实现Builder角色定义的接口的实现类。针对不同的商业逻辑,具体化复杂对象的各部分的创建。在建造完成之后提供产品的实例; 15 | 16 | ●监工(Director) : Director角色负责使用Builder色的接口API来生成实例。内部不涉及具体产品信息,只负责保证对象各部分完整创建或按照某种顺序进行创建。即Director是负责指挥如何build的,只负责调度,具体实施交给具体的建造者; 17 | 18 | ●产品(Product) :即要创建的复杂对象; 19 | 20 | ●使用者(Client) :实际使用Builder模式的角色,即下面的[测试类](./builder_test.go)。 21 | 22 | ### UML类图 23 | 24 | ![](http://www.liuanqihappybirthday.top/uploads/big/c5b045f77f3cdacee4a1db9da8532715.jpg) 25 | 26 | ### 应用场景 27 | 28 | 建造者模式的典型应用场景如下: 29 | 30 | ●产品类非常复杂,不同的调度产生不同的结果时,使用建造者模式比较适合; 31 | 32 | ●相同的组件或配件都可以装配到一个对象,但是产生的结果又不相同,可以使用建造者模式。 33 | 34 | ### 建造者模式VS工厂方法模式 35 | 36 | 建造者模式关注的是零件类型和装配顺序(工艺)同为创建型模式,注重点不同。另外工厂模式只有一个建造方法,而**建造者模式有多个建造零部件的方法并且强调建造顺序,而工厂模式没有顺序的概念。** 37 | 38 | ### 使用实例 39 | 40 | 41 | ```go 42 | import "fmt" 43 | 44 | // 产品类 45 | type Product struct { 46 | ground string 47 | cement string 48 | roof string 49 | } 50 | 51 | func (p *Product) Cement() string { 52 | return p.cement 53 | } 54 | 55 | func (p *Product) SetCement(cement string) { 56 | p.cement = cement 57 | } 58 | 59 | func (p *Product) Roof() string { 60 | return p.roof 61 | } 62 | 63 | func (p *Product) SetRoof(roof string) { 64 | p.roof = roof 65 | } 66 | 67 | func (p *Product) Ground() string { 68 | return p.ground 69 | } 70 | 71 | func (p *Product) SetGround(ground string) { 72 | p.ground = ground 73 | } 74 | 75 | type Builder interface { 76 | BuildGround() 77 | BuildCement() 78 | BuildRoof() 79 | 80 | BuildProduct() *Product 81 | } 82 | 83 | type ConcreteBuilder struct { 84 | p *Product 85 | } 86 | 87 | func (this *ConcreteBuilder) BuildGround() { 88 | this.p.SetGround("建造地基") 89 | fmt.Println(this.p.ground) 90 | } 91 | 92 | func (this *ConcreteBuilder) BuildCement() { 93 | this.p.SetCement("建造房子") 94 | fmt.Println(this.p.Cement()) 95 | } 96 | func (this *ConcreteBuilder) BuildRoof() { 97 | this.p.SetRoof("建造房顶") 98 | fmt.Println(this.p.Roof()) 99 | } 100 | 101 | func (this *ConcreteBuilder) BuildProduct() *Product { 102 | fmt.Println("建造完毕") 103 | return this.p 104 | } 105 | 106 | type Director struct { 107 | builder Builder 108 | } 109 | 110 | func (this *Director) Construst() Product { 111 | this.builder.BuildGround() 112 | this.builder.BuildCement() 113 | this.builder.BuildRoof() 114 | 115 | return *this.builder.BuildProduct() 116 | } 117 | ``` 118 | 119 | 120 | ```go 121 | // 测试 122 | builder := &ConcreteBuilder{p: &Product{}} 123 | 124 | director := &Director{builder: builder} 125 | 126 | director.Construst() 127 | ``` 128 | 129 | 建造地基 130 | 建造房子 131 | 建造房顶 132 | 建造完毕 133 | 134 | 135 | 136 | 137 | 138 | {建造地基 建造房子 建造房顶} 139 | 140 | 141 | 142 | ### 总结 143 | 144 | ![](http://www.liuanqihappybirthday.top/uploads/big/4822afb70940e7caab56390ee2a4c9e6.jpg) 145 | 146 | 147 | ```go 148 | 149 | ``` 150 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/Docs/抽象工厂.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## 抽象工厂模式 5 | 6 | 7 | 抽象工厂模式是工厂模式(简单工厂、工厂方法)中最具抽象和一般性的一种形态。抽象工厂模式可以向客户端提供一个接口, 使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。 8 | 9 | ### **定义** 10 | 11 | 抽象工厂模式的定义:**为创建一组相关或相互依赖的对象提供一个接口,且无须指定它们的具体类。** 12 | 13 | ![](http://www.liuanqihappybirthday.top/uploads/big/cd467410c25cd99a624ad1eed695f90a.jpg) 14 | 15 | **同产品等级是同一类产品,同产品族的产品是由一个工厂生成的。** 16 | 17 | ### **模式特点** 18 | 19 | 抽象工厂模式使用时,一般具有如下特点: 20 | 21 | ●系统中有多个产品族,每个具体工厂负责创建同一族但属于不同产品等级(产品种类)的产品 22 | 23 | ●系统一次只能消费某一族产品,即相同产品族的产品是一起被使用的当系统需要新增一个产品族时,只需要增加新的工厂类即可,无需修改源代码;**但是如果需要产品族中增加一个新种类的产品时,则所有的工厂类都需要修改。** 24 | 25 | 抽象工厂模式中的**抽象工厂类的职责就是定义每个工厂要实现的功能**,即定义多个产品族的产品的创建。这里,同一产品族下有多个产品时,对应的抽象工厂就会有多个抽象方法用来提供创建这些产品的接口。 26 | 27 | ### **抽象工厂的角色** 28 | 29 | 抽象工厂-般包含四种角色,分别是: 30 | 31 | ●抽象工厂(Abstract Factory) :提供了创建产品的接口,包含多个创建产品的方法,即包含多个类似new Product 0的方法; 32 | 33 | ●具体工厂(Concrete Factory) :实现抽象工厂定义的接口,完成某个具体产品的创建; 34 | 35 | ●抽象产品(Abstract Product) :抽象产品定义,-般有多少抽象产品,抽象工厂中就包含多少个创建产品的方法; 36 | 37 | ●具体产品. (Concrete Product) :抽象产品的实现类。 38 | 39 | 实现抽象产品所定义的接口,和具体工厂是多对一的关系: 40 | 41 | ![](http://www.liuanqihappybirthday.top/uploads/big/e29f55abf781438fc4c73d8f6c39512c.jpg) 42 | 43 | 44 | 45 | ### **具体实例:** 46 | 47 | 美的和TCL都会生产TV和空调,这时候,美的和TCL就是两个产品族,TV和空调就是两个产品等级,按照上面的类图照葫芦画瓢就能得到如下的类图。 48 | 49 | ![](http://www.liuanqihappybirthday.top/uploads/big/1a8006b8f0aa5fb48f7b4bc02b44b59b.jpg) 50 | 51 | 52 | ```go 53 | import "fmt" 54 | // 最抽象的一个工厂接口 55 | type Factory interface { 56 | NewTV() Television 57 | NewRefrigerator() Refrigerator 58 | } 59 | // 两个工厂都有的产品的接口 60 | type Television interface { 61 | DoSomething() 62 | } 63 | 64 | type Refrigerator interface { 65 | DoSomething() 66 | } 67 | ``` 68 | 69 | 70 | ```go 71 | // TCL 工厂 72 | type TCLTV struct { 73 | } 74 | 75 | func (TCLTV) DoSomething () { 76 | fmt.Println("TCL电视在Do Something") 77 | } 78 | 79 | type TCLRef struct { 80 | } 81 | 82 | func (TCLRef) DoSomething () { 83 | fmt.Println("TCL空调在do something") 84 | } 85 | 86 | type TCLFactory struct { 87 | } 88 | 89 | func (TCLFactory) NewTV () Television { 90 | return TCLTV{} 91 | } 92 | 93 | func (TCLFactory)NewRefrigerator () Refrigerator { 94 | return TCLRef{} 95 | } 96 | 97 | ``` 98 | 99 | 100 | ```go 101 | // 美的工厂 102 | 103 | type MediaTV struct { 104 | } 105 | 106 | func (MediaTV)DoSomething() { 107 | fmt.Println("美的电视在do something") 108 | } 109 | 110 | type MediaRef struct{} 111 | 112 | func (MediaRef)DoSomething() { 113 | fmt.Println("美的空调在do something") 114 | } 115 | 116 | type MediaFactory struct { 117 | } 118 | 119 | func (MediaFactory) NewTV () Television { 120 | return MediaTV{} 121 | } 122 | 123 | func (MediaFactory)NewRefrigerator () Refrigerator { 124 | return MediaRef{} 125 | } 126 | ``` 127 | 128 | 129 | ```go 130 | // 客户端测试 131 | var ( 132 | factory Factory 133 | ) 134 | // 这里不管是TCL工厂还是美的工厂,因为他们都实现了Factory的接口, 135 | // 所以这两个类都可以直接当做Factory对象来直接使用。 136 | factory = &TCLFactory{} 137 | ref := factory.NewRefrigerator() 138 | ref.DoSomething() 139 | tv := factory.NewTV() 140 | tv.DoSomething() 141 | 142 | factory = MediaFactory{} 143 | ref = factory.NewRefrigerator() 144 | ref.DoSomething() 145 | tv = factory.NewTV() 146 | tv.DoSomething() 147 | ``` 148 | 149 | TCL空调在do something 150 | TCL电视在Do Something 151 | 美的空调在do something 152 | 美的电视在do something 153 | 154 | 155 | 156 | 157 | 假如某天,需要加入海尔的TV和空调,那么只需要对这里做出如下修改就可以了。 158 | 159 | ![](http://www.liuanqihappybirthday.top/uploads/big/2f69a7c6093fa49ab16740897f53001b.jpg) 160 | 161 | ### **总结:** 162 | 163 | ![](http://www.liuanqihappybirthday.top/uploads/big/993a187228c2a3bd0c299982d80bc974.jpg) 164 | 165 | 166 | ```go 167 | 168 | ``` 169 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/Docs/简单工厂模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## 简单工厂模式 5 | 6 | 7 | 8 | ### **意图:** 9 | 10 | 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行 11 | 主要解决接口选择问题 12 | 13 | ### **类图:** 14 | 15 | ![](http://www.liuanqihappybirthday.top/uploads/big/9e71d19fd66298e5a404727f99dc941a.png) 16 | 17 | **返回的实例都实现同一接口** 18 | 19 | ### 应用实例: 20 | 21 | 22 | 23 | 24 | ```go 25 | import "fmt" 26 | 27 | // 定义一个女孩的接口让下面的类隐式继承 28 | type gril interface { 29 | weight() 30 | } 31 | 32 | ``` 33 | 34 | 35 | ```go 36 | type FatGril struct {} 37 | 38 | func (FatGril) weight() { 39 | fmt.Println("100kg") 40 | } 41 | ``` 42 | 43 | 44 | ```go 45 | type ThinGirl struct {} 46 | 47 | func (ThinGirl) weight () { 48 | fmt.Println("45kg") 49 | } 50 | ``` 51 | 52 | 53 | ```go 54 | // 简单工厂 55 | type GirlFactory struct {} 56 | 57 | func (*GirlFactory) CreateGirl (like string) gril { 58 | switch like { 59 | case "fat": 60 | return &FatGril{} 61 | case "thin": 62 | return &ThinGirl{} 63 | default: 64 | return nil 65 | } 66 | } 67 | ``` 68 | 69 | 70 | ```go 71 | // 测试 72 | factor := &GirlFactory{} 73 | 74 | Fat := factor.CreateGirl("fat") 75 | Fat.weight() 76 | Thin := factor.CreateGirl("thin") 77 | Thin.weight() 78 | ``` 79 | 80 | 100kg 81 | 45kg 82 | 83 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/Prototype.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | 4 | //设计一个类的时候,我们通常会使用到构造函数,这里类和对象的关系好比模具和构件的关系, 5 | //对象总是从类中创建的。但是某些场景下是不允许类的调用者直接调用构造函数,也就说对象未 6 | //必需要从类中衍生出来,现实生活中存在太多案例是通过直接“克隆” 来产生新的对象,而且 7 | //克隆出来的本体和克隆体看不出任何区别。 8 | //原型模式不单是一种设计模式,也是一种编程范型。 简单理解原型模式Prototype:不根据类 9 | //来生成实例,而是根据实例生成新的实例。也就说,如果需要一个和某对象一 模一样的对象,那 10 | //么就可以使用原型模式。 11 | import "fmt" 12 | 13 | type Role interface { 14 | Clone() Role 15 | SetHeadColor(string) 16 | SetEyesColor(string) 17 | SetTall(int64) 18 | Show() 19 | } 20 | 21 | type RoleChinese struct { 22 | HeadColor string 23 | EyesColor string 24 | Tall int64 25 | } 26 | 27 | func (pR *RoleChinese) Clone() Role { 28 | var pChinese = &RoleChinese{HeadColor: pR.HeadColor, EyesColor: pR.EyesColor, Tall: pR.Tall} 29 | return pChinese 30 | } 31 | 32 | func (pR *RoleChinese) SetHeadColor(color string) { 33 | pR.HeadColor = color 34 | } 35 | 36 | func (pR *RoleChinese) SetEyesColor(color string) { 37 | pR.EyesColor = color 38 | } 39 | 40 | func (pR *RoleChinese) SetTall(tall int64) { 41 | pR.Tall = tall 42 | } 43 | 44 | func (pR *RoleChinese) Show() { 45 | fmt.Println("Role's headcolor is:", pR.HeadColor, " EyesColor is:", pR.EyesColor, " tall is:", pR.Tall) 46 | } 47 | 48 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/Prototype_test.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | import "testing" 4 | // 因为go语言本身支持指针操作,对于clone的操作还是很方便的 5 | func TestRoleChinese_Clone(t *testing.T) { 6 | role := &RoleChinese{ 7 | HeadColor: "black", 8 | EyesColor: "black", 9 | Tall: 170, 10 | } 11 | role.Show() 12 | copyer := role.Clone() 13 | copyer.Show() 14 | copyer.SetEyesColor("bule") 15 | role.Show() 16 | copyer.Show() 17 | } 18 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/SimpleFactory.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | import "fmt" 4 | 5 | type gril interface { 6 | weight() 7 | } 8 | // 简单工厂模式 9 | type FatGril struct { 10 | } 11 | 12 | func (FatGril) weight() { 13 | fmt.Println("100kg") 14 | } 15 | 16 | type ThinGirl struct { 17 | } 18 | 19 | func (ThinGirl) weight () { 20 | fmt.Println("45kg") 21 | } 22 | 23 | type GirlFactory struct { 24 | } 25 | 26 | func (*GirlFactory) CreateGirl (like string) gril { 27 | switch like { 28 | case "fat": 29 | return &FatGril{} 30 | case "thin": 31 | return &ThinGirl{} 32 | default: 33 | return nil 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/SimpleFactory_test.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | import "testing" 4 | // 简单工厂的测试类 5 | func TestGirlFactory_CreateGirl(t *testing.T) { 6 | factor := &GirlFactory{} 7 | 8 | Fat := factor.CreateGirl("fat") 9 | Fat.weight() 10 | Thin := factor.CreateGirl("thin") 11 | Thin.weight() 12 | } 13 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/Singleton.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | // 单例模式 8 | type ChocolateBoiler struct { 9 | empty bool 10 | boiled bool 11 | } 12 | 13 | var instance *ChocolateBoiler 14 | var once sync.Once 15 | 16 | func GetInstance() *ChocolateBoiler { 17 | // 使用Once保证创建实例的方法永远只能运行一次,就算在并发状态下也一定只执行一次 18 | once.Do(func() { 19 | fmt.Println("锅已创建") 20 | instance = &ChocolateBoiler{true,false} 21 | }) 22 | return instance 23 | } 24 | 25 | func (c *ChocolateBoiler) IsEmpty() bool { 26 | return c.empty 27 | } 28 | 29 | func (c *ChocolateBoiler) IsBoiled() bool { 30 | return c.boiled 31 | } 32 | 33 | func (c *ChocolateBoiler) Fill(){ 34 | if c.empty{ 35 | c.empty = false 36 | fmt.Println("容器装满了") 37 | } 38 | } 39 | 40 | func (c *ChocolateBoiler) Drain(){ 41 | if c.empty==false && c.boiled { 42 | c.empty = true 43 | c.boiled = false 44 | fmt.Println("倒入模具了") 45 | } 46 | } 47 | 48 | func (c *ChocolateBoiler) Boil(){ 49 | if c.empty==false && c.boiled == false { 50 | fmt.Println("巧克力煮开了") 51 | c.boiled = true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/Singleton_test.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | func TestGetInstance(t *testing.T) { 10 | instance = GetInstance() 11 | instance.IsEmpty() 12 | instance.IsBoiled() 13 | 14 | instance.Drain() 15 | 16 | instance.Fill() 17 | instance.Boil() 18 | // 这里再次get会发现返回的依然是我们的instance 19 | instance = GetInstance() 20 | instance.Drain() 21 | var wg sync.WaitGroup 22 | for i:=0;i<10;i++ { 23 | wg.Add(1) 24 | go func() { 25 | instance = GetInstance() 26 | fmt.Println(instance) 27 | wg.Done() 28 | }() 29 | } 30 | wg.Wait() 31 | } 32 | 33 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/abs_test.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | import ( 4 | "testing" 5 | ) 6 | // 抽象工厂的测试类 7 | func TestTCLFactory_NewTV(t *testing.T) { 8 | var factory Factory 9 | factory = &TCLFactory{} 10 | ref := factory.NewRefrigerator() 11 | ref.DoSomething() 12 | tv := factory.NewTV() 13 | tv.DoSomething() 14 | factory = &MediaFactory{} 15 | ref = factory.NewRefrigerator() 16 | ref.DoSomething() 17 | tv = factory.NewTV() 18 | tv.DoSomething() 19 | 20 | } 21 | -------------------------------------------------------------------------------- /DesignPatterns/CreativeType/builder_test.go: -------------------------------------------------------------------------------- 1 | package CreativeType 2 | 3 | import "testing" 4 | 5 | func TestDirector(t *testing.T) { 6 | builder := &ConcreteBuilder{p: &Product{}} 7 | 8 | director := &Director{builder: builder} 9 | 10 | director.Construst() 11 | } 12 | -------------------------------------------------------------------------------- /DesignPatterns/README.MD: -------------------------------------------------------------------------------- 1 | ## 设计模式——golang实现 2 | 3 | > **生活的理想,就是为了理想的生活。 ——张闻天** 4 | 5 | 本项目实现了一共23种设计模式和一个农场模拟需求变更时使用的5个综合的设计模式的小项目 6 | 7 | 本项目包括 8 | 9 | * 23种设计模式源代码和测试文件 10 | * 23种设计模式的文档 11 | * [7大设计原则文档](./七大设计原则.md) 12 | 13 | ### [创造型模式](./CreativeType/Docs) 14 | 15 | 1. 单例模式 16 | * [代码](./CreativeType/Singleton.go) 17 | * [文档](./CreativeType/Docs/单例模式.md) 18 | 19 | 2. 原型模式 20 | * [代码](./CreativeType/Prototype.go) 21 | * [文档](./CreativeType/Docs/原型模式.md) 22 | 23 | 3. 简单工厂 24 | * [代码](./CreativeType/SimpleFactory.go) 25 | * [文档](./CreativeType/Docs/简单工厂模式.md) 26 | 27 | 4. 抽象工厂 28 | * [代码](./CreativeType/AbstractFactory.go) 29 | * [文档](./CreativeType/Docs/抽象工厂.md) 30 | 31 | 5. 建造者模式 32 | * [代码](./CreativeType/Builder.go) 33 | * [文档](./CreativeType/Docs/建造者模式.md) 34 | 35 | 36 | 37 | ### [结构型模式](./StructuralType/Docs) 38 | 39 | 1. 享元模式 40 | * [代码](./StructuralType/Flyweight.go) 41 | * [文档](./StructuralType/Docs/享元模式.md) 42 | 43 | 2. 代理模式 44 | * [代码](./StructuralType/Proxy.go) 45 | * [文档](./StructuralType/Docs/代理模式.md) 46 | 3. 修饰器模式 47 | * [代码](./StructuralType/Decorator.go) 48 | * [文档](./StructuralType/Docs/修饰器模式.md) 49 | 4. 外观模式 50 | * [代码](./StructuralType/Facade.go) 51 | * [文档](./StructuralType/Docs/外观模式.md) 52 | 53 | 5. 桥接模式 54 | * [代码](./StructuralType/Bridge.go) 55 | * [文档](./StructuralType/Docs/桥接模式.md) 56 | 57 | 6. 组合模式 58 | * [代码](./StructuralType/Component.go) 59 | * [文档](./StructuralType/Docs/组合模式.md) 60 | 61 | 62 | 7. 过滤模式 63 | * [代码](./StructuralType/Filter.go) 64 | * [文档](./StructuralType/Docs/过滤模式.md) 65 | 66 | 8. 适配器模式 67 | * [代码](./StructuralType/Wrapper.go) 68 | * [文档](./StructuralType/Docs/适配器模式.md) 69 | 70 | ### [行为型模式](./BehavioralType/Docs) 71 | 72 | 1. 中介者模式 73 | * [代码](./BehavioralType/Mediator.go) 74 | * [文档](./BehavioralType/Docs/中介者模式.md) 75 | 76 | 2. 命令模式 77 | * [代码](./BehavioralType/Command.go) 78 | * [文档](./BehavioralType/Docs/命令模式.md) 79 | 80 | 3. 备忘录模式 81 | * [代码](./BehavioralType/Memento.go) 82 | * [文档](./BehavioralType/Docs/备忘录模式.md) 83 | 84 | 4. 模板方法模式 85 | * [代码](./BehavioralType/Template.go) 86 | * [文档](./BehavioralType/Docs/模板方法模式.md) 87 | 88 | 5. 状态模式 89 | * [代码](./BehavioralType/State.go) 90 | * [文档](./BehavioralType/Docs/状态模式.md) 91 | 92 | 6. 策略模式 93 | * [代码](./BehavioralType/Strategy.go) 94 | * [文档](./BehavioralType/Docs/策略模式.md) 95 | 96 | 7. 观察者模式 97 | * [代码](./BehavioralType/Observer.go) 98 | * [文档](./BehavioralType/Docs/观察者模式.md) 99 | 100 | 8. 解释器模式 101 | * [代码](./BehavioralType/Interpreter.go) 102 | * [文档](./BehavioralType/Docs/解释器模式.md) 103 | 104 | 9. 责任链模式 105 | * [代码](./BehavioralType/Handler.go) 106 | * [文档](./BehavioralType/Docs/责任链模式.md) 107 | 108 | 10. 迭代器模式 109 | * [代码](./BehavioralType/Iterator.go) 110 | * [文档](./BehavioralType/Docs/迭代器模式.md) -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Bridge.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import "fmt" 4 | 5 | type MobilePhone struct { 6 | Impl SoftImplementor 7 | } 8 | 9 | func (MobilePhone) Run() {} 10 | 11 | type SoftImplementor interface { 12 | RawRun() 13 | } 14 | 15 | type GameSoft struct { 16 | SoftImplementor 17 | } 18 | type ChatSoft struct { 19 | SoftImplementor 20 | } 21 | 22 | func (GameSoft)RawRun() { 23 | fmt.Println("游戏软件启动") 24 | } 25 | 26 | func (ChatSoft)RawRun() { 27 | fmt.Println("聊天软件启动") 28 | } 29 | 30 | type HuaWei struct { 31 | MobilePhone 32 | } 33 | 34 | func (h *HuaWei) Run() { 35 | h.Impl.RawRun() 36 | } 37 | 38 | func (h *HuaWei) GPUTurbo() { 39 | fmt.Println("GPUTurbo started") 40 | h.Run() 41 | fmt.Println("GPUTurbo ended") 42 | } 43 | 44 | type XiaoMi struct { 45 | MobilePhone 46 | } 47 | 48 | func (x *XiaoMi) Run() { 49 | x.Impl.RawRun() 50 | } 51 | 52 | func (x *XiaoMi) GameTurbo() { 53 | fmt.Println("GameTurbo started.") 54 | } 55 | 56 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Bridge_test.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import "testing" 4 | 5 | func TestMobilePhone_Run(t *testing.T) { 6 | h1 := HuaWei{MobilePhone{ChatSoft{}}} 7 | h2 := HuaWei{MobilePhone{GameSoft{}}} 8 | h1.Run() 9 | h2.Run() 10 | h2.GPUTurbo() 11 | m1 := XiaoMi{MobilePhone{ChatSoft{}}} 12 | m2 := XiaoMi{MobilePhone{GameSoft{}}} 13 | m1.Run() 14 | m2.Run() 15 | m2.GameTurbo() 16 | } 17 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Component.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import "fmt" 4 | 5 | type MenuComponent interface { 6 | // 采购设备或者添加子部门 7 | Add(menuComponent MenuComponent) 8 | Remove(menuComponent MenuComponent) 9 | // 查询该节点下所有设备和部门 10 | GetName() string 11 | GetPrice() float64 12 | GetDescription() string 13 | IsVegetarian() bool 14 | CreateIterator() 15 | Display(depth int) 16 | } 17 | 18 | type Leaf struct { 19 | name string 20 | vegetarian bool 21 | description string 22 | price float64 23 | } 24 | 25 | func (l *Leaf) Add(menuComponent MenuComponent) { 26 | panic("Leaf Node can not add") 27 | } 28 | 29 | func (l *Leaf) Remove(menuComponent MenuComponent) { 30 | panic("Leaf Node can not remove") 31 | } 32 | 33 | func (l *Leaf) GetName() string { 34 | return l.name 35 | } 36 | 37 | func (l *Leaf) GetPrice() float64 { 38 | return l.price 39 | } 40 | 41 | func (l *Leaf) IsVegetarian() bool { 42 | return l.vegetarian 43 | } 44 | 45 | func (l *Leaf) GetDescription() string { 46 | return l.description 47 | } 48 | 49 | func (l *Leaf) CreateIterator() { 50 | panic("implement me") 51 | } 52 | 53 | 54 | func (l *Leaf) Display(depth int) { 55 | // 输出树形结构的叶子结点,这里直接输出设备名 56 | for i:=0; iString a= "abc"; 7 | String b = "abc"; 8 | System.out.printIn(a == b); // true 9 | 10 | 上述例子中,分别创建两个字符串对象的时候,a、b其实都指向了常量池中的某个字符串"abc”,这种对象创建的模式,就避免了大量对象创建时非必要的资源消耗,享元模式的“享”就有一物被众人所共享的意思,所以享元模式也是池技术的重要实现方式,其定义如下:**使用共享对象有效地支持大量的细粒度的对象。** 11 | 12 | ### 类图 13 | 14 | ![](https://img.mukewang.com/5db7b9eb00018ee309130507.png) 15 | 16 | * 抽象享元角色( Flyweight) : 一般是一个具体的抽象类,同时定义了对象的外部状态和内部状态的接口或实现; 17 | * 具体享元角色( ConcreteFlyweight) :具体的一个产品类,实现了抽象享元角色中定义的接口,该角色需要注意的是内部状态的处理应该与环境无关; 18 | * 享元工厂( FlyweightFactory) :该角色指责一 般比较清晰,就是一个池工厂,提供池对象和获取池中对象的方法 19 | 20 | ### 使用实例——考试 21 | 22 | 23 | ```go 24 | //下面我们用一个最简单的考试报名的例子进行说明,假设我们有2个科目,有3位考生分别进 25 | //行报考,我们一般会定义考试实体ExamInfo,如果不使用模式的话,可以想象,每次有考生参 26 | //与一场科目考试的话,我们就会实例化一个ExamInfo,总共我们要实例化6个这样的实体, 27 | //倘若使用享元模式,我们就只需要实例化2个这样的实体,然后通过内部状态的set方法进行 28 | //不同对象的赋值操作,节省了不少的内存,很神奇吧? 29 | import "fmt" 30 | 31 | type Flyweight interface { 32 | operate() 33 | } 34 | 35 | 36 | type ExamInfo struct { 37 | // 内部状态,用于在不同对象中共享 38 | user string 39 | 40 | // 外部状态,随环境改变而改变 41 | subject string 42 | } 43 | 44 | func (e *ExamInfo) operate() { 45 | fmt.Println(e.user,"开始考试,考试科目为",e.subject) 46 | } 47 | 48 | func (e *ExamInfo) User() string { 49 | return e.user 50 | } 51 | 52 | func (e *ExamInfo) SetUser(user string) { 53 | e.user = user 54 | } 55 | 56 | func (e *ExamInfo) Subject() string { 57 | return e.subject 58 | } 59 | 60 | func (e *ExamInfo) SetSubject(subject string) { 61 | e.subject = subject 62 | } 63 | 64 | func (e *ExamInfo) String () string { 65 | return "ExamInfo{" + 66 | "user = " + e.user + "\n" + 67 | "subject = " + e.subject + "\n" + "}" 68 | } 69 | 70 | // 享元工厂 71 | type ExamInfoFactory struct { 72 | pool map[string]*ExamInfo 73 | } 74 | 75 | func (e *ExamInfoFactory)GetExamInfo(subject string) (Ex *ExamInfo) { 76 | if v,ok := e.pool[subject]; ok { 77 | Ex = v 78 | fmt.Println("直接从池中获取",subject) 79 | } else { 80 | fmt.Println("建立对象,并且放入池中",subject) 81 | Ex = &ExamInfo{subject:subject} 82 | e.pool[subject] = Ex 83 | } 84 | return 85 | } 86 | ``` 87 | 88 | 89 | ```go 90 | import "strconv" 91 | exF := &ExamInfoFactory{ 92 | make(map[string]*ExamInfo), 93 | } 94 | for i := 0; i < 2; i++ { 95 | sub := "科目" + strconv.Itoa(i) 96 | exF.GetExamInfo(sub) 97 | } 98 | 99 | for i := 0; i < 3; i++ { 100 | for j := 0; j < 2; j++ { 101 | // 注意在此嵌套循环中,我们的Examinfo是由工厂返回出来的 102 | // 很显然我们只创建了两次这个对象,而不是像嵌套理所应当的六次 103 | Examinfo := exF.GetExamInfo("科目"+strconv.Itoa(j)) 104 | Examinfo.SetUser("考生"+strconv.Itoa(i)) 105 | fmt.Println(Examinfo) 106 | Examinfo.operate() 107 | } 108 | } 109 | ``` 110 | 111 | 建立对象,并且放入池中 科目0 112 | 建立对象,并且放入池中 科目1 113 | 直接从池中获取 科目0 114 | &{考生0 科目0} 115 | 考生0 开始考试,考试科目为 科目0 116 | 直接从池中获取 科目1 117 | &{考生0 科目1} 118 | 考生0 开始考试,考试科目为 科目1 119 | 直接从池中获取 科目0 120 | &{考生1 科目0} 121 | 考生1 开始考试,考试科目为 科目0 122 | 直接从池中获取 科目1 123 | &{考生1 科目1} 124 | 考生1 开始考试,考试科目为 科目1 125 | 直接从池中获取 科目0 126 | &{考生2 科目0} 127 | 考生2 开始考试,考试科目为 科目0 128 | 直接从池中获取 科目1 129 | &{考生2 科目1} 130 | 考生2 开始考试,考试科目为 科目1 131 | 132 | 133 | ### 总结 134 | 135 | ![](https://img.mukewang.com/5db7ba030001088a12400682.png) 136 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Docs/代理模式.md: -------------------------------------------------------------------------------- 1 | 2 | ## 代理模式 3 | 4 | 代理模式的定义其实比较简单:代理模式给某对象提供一个代理对象,由代理对象来控制对原对象的引用。生活中比较常见的代理模式的应用比如:火车票代购、代办保险、UU跑腿、武侠片中的替身、nginx反向代理等等这种类似于中介的模式统统可以归于代理模式。“本人” 和“代理人”都是对象,“ 代理人”可以代替“本人”去完成一些工作,甚至是出色完成( 超期完成)某些工作,这里的“出色完成”就可以理解为对原工作的一种增强实现,这点有点类似于装饰器模式。 5 | 6 | 那么,为什么会存在代理模式呢?我们知道,存在即合理,很多情况下,客户类不想或不能直接用委托对象,这时候使用代理类充当中介作用,这种情况下代理类和委托类实现相同的接口;另外,有时候我们会想增强委托类,这个时候使用代理类来完成也是再合适不过了,也是符合开闭原则(对拓展开放,对修改关闭)的。 7 | 8 | 9 | ### 类图 10 | 11 | ![](https://img.mukewang.com/5db7e22d00019f6b05020285.png) 12 | 13 | 代理模式也叫做委托模式,代理类一般包含被委托类的引用,我们来说下上面三个角色的定义: 14 | * 抽象主题角色( Subject) :抽象主题角色往往是一个抽象类或接口,用来定义被委托类也就是真实的业务处理类和代理类的一些通用操作 ; 15 | * 具体的主题角色( RealSubject) :该类实现Subject,是真实被委托的类,也是具体业务逻辑的真正执行者; 16 | * 代理类或委托类(Proxy) :该类同样实现Subject,在客户类和本地之间充当中介作用,将客户端的业务操作委托给RealSubject执行,并在执行前后做一些预处理或者善后工作。 有点类似于AOP,实际上AOP使用的也是代理模式,不过是动态代理。 17 | 18 | ### 使用实例--购票 19 | 20 | 21 | 22 | ![](https://img.mukewang.com/5db7e25b0001123106740387.png) 23 | 24 | 25 | ```go 26 | import "fmt" 27 | 28 | type IBuyer interface { 29 | Login(username,password string) 30 | BuyTicket() 31 | } 32 | 33 | type BuyerProxy struct { 34 | b *Buyer 35 | } 36 | 37 | func (b *BuyerProxy)Login(username,password string) { 38 | b.b.Login(username,password) 39 | } 40 | func (b *BuyerProxy)BuyTicket() { 41 | before() 42 | b.b.BuyTicket() 43 | after() 44 | } 45 | 46 | func before() { 47 | fmt.Println("准备定时任务,开始刷票") 48 | } 49 | 50 | func after() { 51 | fmt.Println("刷票成功,短信通知用户") 52 | } 53 | 54 | type Buyer struct { 55 | name string 56 | } 57 | 58 | func (b *Buyer)Login(username,password string) { 59 | fmt.Println(b.name,"使用",username,"登陆成功") 60 | } 61 | 62 | func (b *Buyer)BuyTicket() { 63 | fmt.Println(b.name,"购票成功") 64 | } 65 | ``` 66 | 67 | 68 | ```go 69 | buyer := &Buyer{name: "123"} 70 | proxy := BuyerProxy{b: buyer} 71 | proxy.Login("678","345") 72 | proxy.BuyTicket() 73 | ``` 74 | 75 | ```go 76 | 123 使用 678 登陆成功 77 | 准备定时任务,开始刷票 78 | 123 购票成功 79 | 刷票成功,短信通知用户 80 | --- PASS: TestBuyer_BuyTicket (0.00s) 81 | ``` 82 | ### 总结 83 | 84 | ![](https://img.mukewang.com/5db7e2720001f36f10430731.png) 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Docs/外观模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## 外观模式 5 | 6 | ### 定义 7 | 想象一下 ,我们系统随着时间的推移,系统复杂性、类之间的相互调用会变得越来越多,相比较客户角度而言,客户往往关注的是某个单一接口API, 而不会关心该API内部的复杂性或者内部子系统是如何运作的。 8 | 9 | 举个栗子,我们都玩过射击类游戏,游戏玩家对战的时候,需要进行射击操作,而射击牵扯到一连串的动作,比如:上子弹、瞄准、发射子弹、掉血、加分等等一系列动作, 这些动作我们可以理解为各个子系统的某个接口API,比如上子弹、发射子弹可能是武器子系统的API,掉血、加分可能是用户子系统的API,客户角度需要调用的接口其实只有一个,那就是射击API,这就是具体的门面接口,门面内部的各个子系统的动作对客户是透明的,这种客户只需要调用门面接口API就实现了一连串内部动作(上子弹、瞄准、发射子弹、掉血、加分等)的模式其实就叫做外 10 | 观模式,也叫做门面模式。 11 | 12 | 外观模式的定义是:为各个子系统的一组接口提供一致的调用窗口或门面,使得子系统更容易使用,使得复杂的子系统与客户端分离解耦。 13 | 14 | ### 类图 15 | 16 | ![](https://img1.sycdn.imooc.com/5db7b9430001ffd408490399.png) 17 | 18 | ●门面角色(Facade) :门面模式自然少不了门面角色,这就是我们的Facade类,一般情况下,该角色会将客户端的请求委派给相应的子系统去调用,也就说该角色实际没有啥实质性的业务逻辑,只是一个单纯的委派类,用来实现客户端和子系统的解耦; 19 | 20 | ●子系统角色( SubSystem) :子系统并不是一个单一 的类,而是众多类的一个系统集合。一般而言,子系统并不知道门面角色的存在,也就说对子系统而言,门面角色是完全透明的。子系统各自实现自己的功能,包括类之间的相互调用等,这些都不受门面角色的影响。 21 | 22 | ### 使用实例,射击游戏 23 | 24 | ![](https://img1.sycdn.imooc.com/5db7b932000197c908810542.png) 25 | 26 | 27 | 4、优缺点 28 | 外观模式优点: 29 | 30 | ●实现了子系统与客户端之间关系的解耦; 31 | 32 | ●客户端屏蔽了子系统组件,使得客户端所需处理的对象数目有所减少,使得子系统使用起来更加容易。 33 | 34 | 外观模式缺点: 35 | 36 | ●增加新的子系统可能需要修改外观类或者客户端的源代码,违背了开闭原则; 37 | 38 | ●外观类并没有阻断子系统被外部使用的可能性。 39 | 40 | 41 | 42 | ```go 43 | import ( 44 | "fmt" 45 | ) 46 | 47 | type GunSystem struct { 48 | } 49 | 50 | func (GunSystem)Fire() { 51 | fmt.Println("开火") 52 | } 53 | 54 | func (GunSystem)UseBullet() { 55 | fmt.Println("上子弹") 56 | } 57 | 58 | type UserSystem struct { 59 | } 60 | 61 | func (UserSystem)AddScore() { 62 | fmt.Println("得分") 63 | } 64 | 65 | func (UserSystem)LoseBlood() { 66 | fmt.Println("掉血") 67 | } 68 | 69 | type Facade struct { 70 | fire *GunSystem 71 | user *UserSystem 72 | } 73 | 74 | func (f *Facade) shooting() { 75 | f.fire.Fire() 76 | f.fire.UseBullet() 77 | f.user.AddScore() 78 | f.user.LoseBlood() 79 | } 80 | ``` 81 | 82 | 83 | ```go 84 | facade := &Facade{ 85 | fire: &GunSystem{}, 86 | user: &UserSystem{}, 87 | } 88 | facade.shooting() 89 | ``` 90 | 91 | 开火 92 | 上子弹 93 | 得分 94 | 掉血 95 | 96 | 97 | ### 总结 98 | 99 | ![](https://img1.sycdn.imooc.com/5db7b95200015e1512470553.png) 100 | 101 | 102 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Docs/桥接模式.md: -------------------------------------------------------------------------------- 1 | ## 桥接模式 2 | 3 | ### 定义 4 | 5 | 桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式, 又称为柄体(Handle and Body)模式或接口(Interface) 模式。 6 | 7 | Bridge的意思就是“桥梁”, 好比现实生活中的桥梁, 它的存在就是将河流两侧东西给连接起来,应用到软件里面Bridge就是将**类的功能层次结构与实现层次结构连接起来。** 8 | 9 | ### UML类图 10 | 11 | ![](https://img1.sycdn.imooc.com/5db146f20001437210430651.png) 12 | 13 | 桥接模式中包含了几种角色,分别是: 14 | 15 | ●抽象化(Abstraction) :该角色位于属于"类的功能层次结构” 的最上层,用于定义抽象接口,一般是抽象类而不是抽象接口。其内部往往包含一个实现类接口实例(Implementor),使用委托方式进行内部调用; 16 | 17 | ●改善后的抽象化,或者叫补充抽象类(RefinedAbstraction) :该角色用于补充 18 | Abstraction功能而存在,通常情况下不再是抽象类而是具体的实现类,在内部可以直接调用Implementor中的业务方法; 19 | 20 | ●实现者(Implementor) :该角色位于"类的实现层次结构” 的最上层,定义了用于实现Abstraction角色的接口(API) ,这里的接口并非要和Abstraction中定义的完全一致,Implementor只对这些接口进行声明,具体实现还是要交给子类。通过委托,在 21 | Abstraction中,不仅可以调用自己方法,还可以调用到Implementor中定义的方法; 22 | 23 | ●具体实现者(Concretelmplementor) :该角色用于实现Implementor角色中定义的接口,不同的实现类提供不同的业务处理方法,程序运行时,Concretelmplementor 将替换Abstraction中的Implementor,提供给抽象类具体的业务操作方法。 24 | 25 | ### 实例 26 | 27 | 我们的手机上都安装了各种各样的软件,我们如何表示“在手机上运行软件”这一活动?手机的品牌和软件是两个维度上的东西,我们将其类比成功能层级和实现层级。类图如下 28 | 29 | ![](https://img1.sycdn.imooc.com/5dbac89600014e8710240355.png) 30 | 31 | 测试方法 32 | 33 | ```go 34 | package StructuralType 35 | 36 | import "testing" 37 | 38 | func TestMobilePhone_Run(t *testing.T) { 39 | h1 := HuaWei{MobilePhone{ChatSoft{}}} 40 | h2 := HuaWei{MobilePhone{GameSoft{}}} 41 | h1.Run() 42 | h2.Run() 43 | h2.GPUTurbo() 44 | m1 := XiaoMi{MobilePhone{ChatSoft{}}} 45 | m2 := XiaoMi{MobilePhone{GameSoft{}}} 46 | m1.Run() 47 | m2.Run() 48 | m2.GameTurbo() 49 | } 50 | ``` 51 | 52 | 测试结果 53 | 54 | ``` 55 | === RUN TestMobilePhone_Run 56 | 聊天软件启动 57 | 游戏软件启动 58 | GPUTurbo started 59 | 聊天软件启动 60 | 游戏软件启动 61 | GameTurbo started. 62 | --- PASS: TestMobilePhone_Run (0.00s) 63 | PASS 64 | ``` 65 | 66 | 由于m1、m2都属于MobilePhoneAbstraction的类的实例,因此我们可以调用它们的run方法,而m1、m2又都属于HuaWeiMobilePhone的实例,所以我们还能调用其gpuTurborRun方法,比如后期我们run实现有所变动,那么只需要修改main方法和Softlmplementor的实现类即可,其它代码就可以保持不动了。 67 | 68 | 通过MobilePhoneAbstraction中的impl桥接,就实现了抽象与行为实现的分离,这种就是桥接模式的存在意义。 69 | 70 | ### 优缺点 71 | 72 | 桥接模式的优缺点总结如下: 73 | ●抽象与实现相分离:抽象与实现相分离,从而让抽象与实现分别独立开来,分别定义接口,有助于系统分层及产生更好的结构化系统; 74 | 75 | ●更好的拓展性:系统拓展时,因为抽象与实现已经分别独立,所以可以进行分别拓展不会相互影响,从而大大提高系统拓展性。 76 | 77 | ### 总结 78 | 79 | ![](https://img1.sycdn.imooc.com/5db1471a00016b9007460219.png) -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Docs/组合模式.md: -------------------------------------------------------------------------------- 1 | ## 组合模式 2 | 3 | 组合模式指的是**局部-整体**的关系,比如火车车厢离开了火车就没有存在的意义。 4 | 5 | 组合模式常常拿来与聚合作比较,聚合指代的是**整体-局部**的关系,其中局部可以脱离整体而单独存在,比如班级如果解散了,学生的单独存在是有意义的。 6 | 7 | 这是一个理想情况下可无限循环的结构体,组合模式的出现就是为了让我们以一致的方式来处理个别对象亦或者组合对象,而不必区分对象类型。也就是说,当我们 用到树形结构或者类似的“部分-整体”关系的时候我们就可以使用组合模式。 8 | 9 | ![](https://img1.sycdn.imooc.com/5db7b773000157d610180416.png) 10 | 11 | ### 组合模式的UML图 12 | 13 | ![](https://img1.sycdn.imooc.com/5db7b77f0001a27511010611.png) 14 | 15 | ### 组成角色 16 | 17 | ![](https://img1.sycdn.imooc.com/5db7b7900001bfe516780457.png) 18 | 19 | ### 使用实例 20 | 21 | 接下来,我们通过一个实例来说明下什么是组合模式?比方拿我们以前实验室来说,说我们有很多实验部门,每个部底下会管理多台实验设备,每个部门底下又会存在多个子部门,使用图例描述如下: 22 | 23 | ![](https://img1.sycdn.imooc.com/5db7b7a00001cb3310330515.png) 24 | 25 | 组合模式组合多个对象成树形结构以表示“部分整体”关系的层次结构,**使得我们能以一致的方式来处理单个对象及对象的组合,而无需关心处理的是单个对象还是某个复合对象。** 26 | 27 | ### 总结 28 | ![](https://img1.sycdn.imooc.com/5db7b7d4000151d016970356.png) -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Docs/适配器模式.md: -------------------------------------------------------------------------------- 1 | 2 | ## 适配器模式 3 | 4 | ### 定义 5 | 6 | 适配器,其实很好理解,生活中也随处可见,比如电源适配器、usb 适配器等等,那么适配器模式,也被称为Wrapper模式。 7 | 8 | Wrapper有“包装器”的意思,适配器模式的定义是:**将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,解决的痛点便是因接口不兼容导致的类不能正常工作的问题。** 9 | 10 | ![](http://www.liuanqihappybirthday.top/uploads/big/1b3391b9b7e5100614206acbc732e90b.png) 11 | 12 | 如上图所示,A、B代表已经成型的物体,如果这两个物体想要安装在一起,因为两者接口不兼容,不可能直接安装在一起,这时候怎么办?我们就可以通过引入一个物体C,物体C既要适配A也要适配B的接口。 13 | 14 | 什么时候使用适配器模式,从上面的案例我们也可以看出一点端倪: 15 | 16 | ● 现有的类或接口不能满足需求,且一般无法直接修改现有类或接口。比方该类为三方提供,就无法修改,亦或者像A、B这种已经塑模成型的物件,可能已大规模在使用中,所以不允许修改。 17 | 18 | ● 想要建立一个可以重复使用的类,用于与-些彼此之间没有太大关联的一些类,包括-些可能在将来引进的类一起工作,这些源类不一定有一致的接口。 19 | 20 | ### 组成角色 21 | 22 | ![](http://www.liuanqihappybirthday.top/uploads/big/38243f22a6520b11632da2da23d054dc.png) 23 | 24 | ●目标角色(Target) :该角色定义把其它类转换为何种接口,也就是我们的期望接口,可以是一个抽象类或接口,也可以是具体类。 25 | 26 | ●适配器角色(Adapter) :适配器可以调用另-一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,通常都是一个具体的类。 27 | 28 | ●源角色(被适配Adaptee) :你想把谁转换成目标角色,这个“谁”就是源角色,它是已经存在的、运行良好的类或对象,经过适配器角色的包装,它会成为一个崭新、靓丽的角色。 29 | 30 | ●请求者(Client) :该角色负责使用Target定义的方法进行具体处理。 31 | 32 | ### 类适配器(使用继承) 33 | 34 | ![](http://www.liuanqihappybirthday.top/uploads/big/0feccc9fa922530048ee1d88bd06fcf5.png) 35 | 36 | ### 优缺点 37 | 38 | 主要优点: 39 | ●将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构; 40 | 41 | ●增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用; 42 | 43 | ●可以将两个互不相干的类关联在一起; 44 | 45 | ●增强系统灵活性。 46 | 47 | 主要缺点: 48 | ●类适配器对于Java、C#等不支持多重类继承的语言,一次最多只能适配一个适配者类,不能同时适配多个适配者。 49 | 50 | ### 总结 51 | 52 | ![](https://img.mukewang.com/5db14584000195ff06350366.png) -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Facade.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type GunSystem struct { 8 | } 9 | 10 | func (GunSystem)Fire() { 11 | fmt.Println("开火") 12 | } 13 | 14 | func (GunSystem)UseBullet() { 15 | fmt.Println("上子弹") 16 | } 17 | 18 | type UserSystem struct { 19 | } 20 | 21 | func (UserSystem)AddScore() { 22 | fmt.Println("得分") 23 | } 24 | 25 | func (UserSystem)LoseBlood() { 26 | fmt.Println("掉血") 27 | } 28 | 29 | type Facade struct { 30 | fire *GunSystem 31 | user *UserSystem 32 | } 33 | 34 | func (f *Facade) shooting() { 35 | f.fire.Fire() 36 | f.fire.UseBullet() 37 | f.user.AddScore() 38 | f.user.LoseBlood() 39 | } 40 | 41 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Facade_test.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import "testing" 4 | 5 | func TestGunSystem_Fire(t *testing.T) { 6 | facade := &Facade{ 7 | fire: &GunSystem{}, 8 | user: &UserSystem{}, 9 | } 10 | facade.shooting() 11 | } 12 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Filter.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | type Rubbish struct { 4 | name string 5 | isHarm bool 6 | isRecycled bool 7 | isDry bool 8 | isWet bool 9 | } 10 | 11 | // 我们过滤的标准接口,即一个抽象的过滤器 12 | type Criteria interface { 13 | // 定义过滤的标准 14 | RubbishFilter(rubbishs []Rubbish) []Rubbish 15 | } 16 | 17 | // 具体的过滤类 18 | // 干垃圾 19 | type DryRubbishCriteria struct {} 20 | 21 | func (DryRubbishCriteria)RubbishFilter(rubbishs []Rubbish) []Rubbish { 22 | res := make([]Rubbish,0) 23 | for _,v := range rubbishs { 24 | if v.isDry == true { 25 | res = append(res,v) 26 | } 27 | } 28 | return res 29 | } 30 | 31 | // 湿垃圾 32 | type WetRubbishCriteria struct {} 33 | 34 | func (WetRubbishCriteria)RubbishFilter(rubbishs []Rubbish) []Rubbish { 35 | res := make([]Rubbish,0) 36 | for _,v := range rubbishs { 37 | if v.isWet == true { 38 | res = append(res,v) 39 | } 40 | } 41 | return res 42 | } 43 | 44 | // 有害垃圾 45 | type HarmfulRubbishCriteria struct {} 46 | 47 | func (HarmfulRubbishCriteria)RubbishFilter(rubbishs []Rubbish) []Rubbish { 48 | res := make([]Rubbish,0) 49 | for _,v := range rubbishs { 50 | if v.isHarm == true { 51 | res = append(res,v) 52 | } 53 | } 54 | return res 55 | } 56 | 57 | // 可回收垃圾 58 | type RecycledRubbishCriteria struct {} 59 | 60 | func (RecycledRubbishCriteria)RubbishFilter(rubbishs []Rubbish) []Rubbish { 61 | res := make([]Rubbish,0) 62 | for _,v := range rubbishs { 63 | if v.isRecycled == true { 64 | res = append(res,v) 65 | } 66 | } 67 | return res 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Filter_test.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestHarmfulRubbishCriteria_RubbishFilter(t *testing.T) { 8 | rub := make([]Rubbish,0) 9 | rub = append(rub,Rubbish{ 10 | name: "果壳", 11 | isHarm: false, 12 | isRecycled: false, 13 | isDry: true, 14 | isWet: false, 15 | }) 16 | rub = append(rub,Rubbish{"陶瓷",false,false,true,false}) 17 | rub = append(rub,Rubbish{"菜根菜叶",false,false,false,true}) 18 | rub = append(rub,Rubbish{"果皮",false,false,false,true}) 19 | rub = append(rub,Rubbish{"水银温度计",true,false,false,false}) 20 | rub = append(rub,Rubbish{"电池",true,false,false,false}) 21 | rub = append(rub,Rubbish{"灯泡",true,false,false,false}) 22 | rub = append(rub,Rubbish{"废纸塑料",false,true,false,false}) 23 | rub = append(rub,Rubbish{"金属和布料",false,true,false,false}) 24 | rub = append(rub,Rubbish{"玻璃",false,true,false,false}) 25 | 26 | dryFilter := DryRubbishCriteria{} 27 | wetFilter := WetRubbishCriteria{} 28 | harmFilter := HarmfulRubbishCriteria{} 29 | recyFilter := RecycledRubbishCriteria{} 30 | 31 | t.Log(dryFilter.RubbishFilter(rub)) 32 | t.Log(wetFilter.RubbishFilter(rub)) 33 | t.Log(harmFilter.RubbishFilter(rub)) 34 | t.Log(recyFilter.RubbishFilter(rub)) 35 | 36 | } 37 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Flyweight.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import "fmt" 4 | 5 | // 享元模式是以共享的模式来支持大量细粒度对象的复用。听起来可能有点绕 6 | // 其实java中的string就是一个享元模式 7 | // String a = "abc"; 8 | // String b = "abc"; 9 | // System.out.pirntln(a==b) 会得到一个true 10 | // 上面的例子中,a,b其实被创建的时候,都指向了常量池中某个字符串"abc" 11 | 12 | //下面我们用一个最简单的考试报名的例子进行说明,假设我们有2个科目,有3位考生分别进 13 | //行报考,我们一般会定义考试实体ExamInfo,如果不使用模式的话,可以想象,每次有考生参 14 | //与一场科目考试的话,我们就会实例化一个ExamInfo,总共我们要实例化6个这样的实体, 15 | //倘若使用享元模式,我们就只需要实例化2个这样的实体,然后通过内部状态的set方法进行 16 | //不同对象的赋值操作,节省了不少的内存,很神奇吧? 17 | type Flyweight interface { 18 | operate() 19 | } 20 | 21 | 22 | type ExamInfo struct { 23 | // 内部状态,用于在不同对象中共享 24 | user string 25 | 26 | // 外部状态,随环境改变而改变 27 | subject string 28 | } 29 | 30 | func (e *ExamInfo) operate() { 31 | fmt.Println(e.user,"开始考试,考试科目为",e.subject) 32 | } 33 | 34 | func (e *ExamInfo) User() string { 35 | return e.user 36 | } 37 | 38 | func (e *ExamInfo) SetUser(user string) { 39 | e.user = user 40 | } 41 | 42 | func (e *ExamInfo) Subject() string { 43 | return e.subject 44 | } 45 | 46 | func (e *ExamInfo) SetSubject(subject string) { 47 | e.subject = subject 48 | } 49 | 50 | func (e *ExamInfo) String () string { 51 | return "ExamInfo{" + 52 | "user = " + e.user + "\n" + 53 | "subject = " + e.subject + "\n" + "}" 54 | } 55 | 56 | // 享元工厂 57 | type ExamInfoFactory struct { 58 | pool map[string]*ExamInfo 59 | } 60 | 61 | func (e *ExamInfoFactory)GetExamInfo(subject string) (Ex *ExamInfo) { 62 | if v,ok := e.pool[subject]; ok { 63 | Ex = v 64 | fmt.Println("直接从池中获取",subject) 65 | } else { 66 | fmt.Println("建立对象,并且放入池中",subject) 67 | Ex = &ExamInfo{subject:subject} 68 | e.pool[subject] = Ex 69 | } 70 | return 71 | } -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Flyweight_test.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "testing" 7 | ) 8 | 9 | func TestExamInfo_Subject(t *testing.T) { 10 | exF := &ExamInfoFactory{ 11 | make(map[string]*ExamInfo), 12 | } 13 | for i := 0; i < 2; i++ { 14 | sub := "科目" + strconv.Itoa(i) 15 | exF.GetExamInfo(sub) 16 | } 17 | 18 | for i := 0; i < 3; i++ { 19 | for j := 0; j < 2; j++ { 20 | // 注意在此嵌套循环中,我们的Examinfo是由工厂返回出来的 21 | // 很显然我们只创建了两次这个对象,而不是像嵌套理所应当的六次 22 | Examinfo := exF.GetExamInfo("科目"+strconv.Itoa(j)) 23 | Examinfo.SetUser("考生"+strconv.Itoa(i)) 24 | fmt.Println(Examinfo) 25 | Examinfo.operate() 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Proxy.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import "fmt" 4 | 5 | type IBuyer interface { 6 | Login(username,password string) 7 | BuyTicket() 8 | } 9 | 10 | type BuyerProxy struct { 11 | b *Buyer 12 | } 13 | 14 | func (b *BuyerProxy)Login(username,password string) { 15 | b.b.Login(username,password) 16 | } 17 | func (b *BuyerProxy)BuyTicket() { 18 | before() 19 | b.b.BuyTicket() 20 | after() 21 | } 22 | 23 | func before() { 24 | fmt.Println("准备定时任务,开始刷票") 25 | } 26 | 27 | func after() { 28 | fmt.Println("刷票成功,短信通知用户") 29 | } 30 | 31 | type Buyer struct { 32 | name string 33 | } 34 | 35 | func (b *Buyer)Login(username,password string) { 36 | fmt.Println(b.name,"使用",username,"登陆成功") 37 | } 38 | 39 | func (b *Buyer)BuyTicket() { 40 | fmt.Println(b.name,"购票成功") 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Proxy_test.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import "testing" 4 | 5 | func TestBuyer_BuyTicket(t *testing.T) { 6 | buyer := &Buyer{name: "123"} 7 | proxy := BuyerProxy{b: buyer} 8 | proxy.Login("678","345") 9 | proxy.BuyTicket() 10 | } 11 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Wrapper.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import "fmt" 4 | 5 | type Duck interface { 6 | Quack() 7 | Fly() 8 | } 9 | 10 | type Turkey interface { 11 | Gobble() 12 | TurkeyFly() 13 | } 14 | 15 | type Adaptee struct {} 16 | 17 | func (a Adaptee) Gobble() { 18 | fmt.Println("火鸡咕咕叫") 19 | } 20 | 21 | func (a Adaptee) TurkeyFly() { 22 | fmt.Println("火鸡起飞") 23 | } 24 | 25 | type Adapter struct { 26 | Adaptee 27 | } 28 | 29 | func (a Adapter) Quack() { 30 | fmt.Println("鸭子嘎嘎叫") 31 | } 32 | 33 | func (a Adapter) Fly() { 34 | fmt.Println("鸭子嘎嘎叫") 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /DesignPatterns/StructuralType/Wrapper_test.go: -------------------------------------------------------------------------------- 1 | package StructuralType 2 | 3 | import "testing" 4 | 5 | func TestAdapter_TargetMethod1(t *testing.T) { 6 | adapter := Adapter{} 7 | 8 | adapter.Quack() 9 | adapter.Gobble() 10 | adapter.Fly() 11 | adapter.TurkeyFly() 12 | } 13 | -------------------------------------------------------------------------------- /DoubleLinked/FIFO.go: -------------------------------------------------------------------------------- 1 | package DoubleLinked 2 | 3 | import "fmt" 4 | 5 | type FIFOCache struct { 6 | capacity int 7 | size int 8 | list *List 9 | find map[interface{}]*Node 10 | k int 11 | // count记录缺页中断的次数 12 | count int 13 | } 14 | 15 | func InitFIFO(capacity int) *FIFOCache { 16 | return &FIFOCache{ 17 | capacity: capacity, 18 | find: map[interface{}]*Node{}, 19 | list: InitList(capacity), 20 | } 21 | } 22 | 23 | func (this *FIFOCache)GetCount() int { 24 | return this.count 25 | } 26 | 27 | func (this *FIFOCache)Get(key interface{}) interface{} { 28 | if value,ok := this.find[key];!ok{ 29 | this.k = this.k%this.capacity 30 | node := this.list.head 31 | for i:=0;i b { 57 | return b 58 | } 59 | return a 60 | }(min,key) 61 | } 62 | return min 63 | } 64 | func (this *LFUCache)Get(key interface{}) interface{} { 65 | if _,ok := this.find[key]; !ok { 66 | min_freq := findMinNum(this.freq_map) 67 | list := this.freq_map[min_freq] 68 | node := list.head 69 | fmt.Println("发生了一次缺页中断") 70 | // 先取到这个节点的地址 71 | newNode := this.find[node.key] 72 | // 从节点的映射中删掉这个节点 73 | delete(this.find,node.key) 74 | // 赋值新的key 75 | newNode.node.key = key 76 | this.find[key] = newNode 77 | // 在链表中真正的删除这个节点,并且删除后如果链表的长度为0,在频率映射表中吧这个链表删掉 78 | list.Remove(newNode.node) 79 | if list.size == 0{ 80 | delete(this.freq_map,newNode.freq) 81 | } 82 | newNode.freq = 0 83 | if _,ok := this.freq_map[0]; !ok { 84 | this.freq_map[0] = InitList(10) 85 | } 86 | this.freq_map[0].Append(newNode.node) 87 | this.updateFreq(newNode) 88 | this.count++ 89 | return -1 90 | } 91 | node := this.find[key] 92 | this.updateFreq(node) 93 | return node.node.value 94 | } 95 | 96 | func (this *LFUCache) Put (key,value interface{}) { 97 | if this.capacity == 0 { 98 | return 99 | } 100 | // 命中缓存 101 | if _,ok := this.find[key] ; ok { 102 | node := this.find[key] 103 | node.node.value = value 104 | this.updateFreq(node) 105 | } else { 106 | if this.capacity == this.size { 107 | // 找到一个最小的频率 108 | min_freq := findMinNum(this.freq_map) 109 | node := this.freq_map[min_freq].Pop() 110 | lfuNode := &LFUNode{ 111 | node:node, 112 | freq:1, 113 | } 114 | this.find[key] = lfuNode 115 | delete(this.find,node.key) 116 | this.size-- 117 | } 118 | node := InitLFUNode(key,value) 119 | node.freq = 1 120 | this.find[key] = node 121 | if _,ok := this.freq_map[node.freq]; !ok { 122 | this.freq_map[node.freq] = InitList(math.MaxInt32) 123 | } 124 | node.node = this.freq_map[node.freq].Append(node.node) 125 | this.size++ 126 | } 127 | } 128 | 129 | func (this *LFUCache)String() string { 130 | builder := strings.Builder{} 131 | fmt.Fprintln(&builder,"*******************") 132 | for k,v := range this.freq_map { 133 | fmt.Fprintf(&builder,"Freq = %d\n",k) 134 | fmt.Fprintln(&builder,v.String()) 135 | } 136 | fmt.Fprintln(&builder,"*******************") 137 | return builder.String() 138 | } -------------------------------------------------------------------------------- /DoubleLinked/LFU_test.go: -------------------------------------------------------------------------------- 1 | package DoubleLinked 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func TestInitLFUCahe(t *testing.T) { 11 | var ( 12 | file *os.File 13 | err error 14 | ) 15 | if file, err = os.Open("test.txt"); err != nil { 16 | return 17 | } 18 | defer file.Close() 19 | LFU := InitLFUCahe(3) 20 | for i:=0;i<3;i++ { 21 | var key int 22 | fmt.Fscanf(file,"%d",&key) 23 | LFU.Put(key,rand.Intn(100)) 24 | } 25 | t.Log(LFU) 26 | for { 27 | var key int 28 | if _,err = fmt.Fscanf(file,"%d",&key);err!=nil{ 29 | break 30 | } else { 31 | t.Log(LFU.Get(key)) 32 | } 33 | t.Log(LFU.String()) 34 | } 35 | t.Log("程序正常退出,一共发生",LFU.count,"次缺页中断") 36 | } 37 | -------------------------------------------------------------------------------- /DoubleLinked/LRU.go: -------------------------------------------------------------------------------- 1 | package DoubleLinked 2 | 3 | import "fmt" 4 | 5 | type LRUCache struct { 6 | capacity int 7 | find map[interface{}]*Node 8 | list *List 9 | k int 10 | count int 11 | } 12 | 13 | func InitLRU(capacity int) *LRUCache { 14 | return &LRUCache{ 15 | capacity: capacity, 16 | list: InitList(capacity), 17 | find: make(map[interface{}]*Node), 18 | } 19 | } 20 | 21 | func (this *LRUCache)Get(key interface{}) interface{} { 22 | if value,ok := this.find[key];ok{ 23 | node := value 24 | this.list.Remove(node) 25 | this.list.AppendToHead(node) 26 | return node.value 27 | } else { 28 | this.k = this.k%this.capacity 29 | node := this.list.head 30 | for i:=0;i= this.list.capacity { 53 | oldNode := this.list.Remove(nil) 54 | delete(this.find,oldNode.value) 55 | } 56 | this.list.AppendToHead(node) 57 | this.find[key] = node 58 | } 59 | } 60 | 61 | func (this *LRUCache)String() string { 62 | return this.list.String() 63 | } -------------------------------------------------------------------------------- /DoubleLinked/LRU_test.go: -------------------------------------------------------------------------------- 1 | package DoubleLinked 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func TestLRUCache(t *testing.T) { 11 | var ( 12 | file *os.File 13 | err error 14 | ) 15 | if file, err = os.Open("test.txt"); err != nil { 16 | return 17 | } 18 | defer file.Close() 19 | LRU := InitLRU(3) 20 | for i:=0;i<4;i++ { 21 | var key int 22 | fmt.Fscanf(file,"%d",&key) 23 | LRU.Put(key,rand.Intn(100)) 24 | } 25 | t.Log(LRU) 26 | for { 27 | var key int 28 | if _,err = fmt.Fscanf(file,"%d",&key);err!=nil{ 29 | break 30 | } else { 31 | LRU.Get(key) 32 | } 33 | t.Log(LRU.String()) 34 | } 35 | t.Log("程序正常退出,一共发生",LRU.count,"次缺页中断") 36 | } 37 | -------------------------------------------------------------------------------- /DoubleLinked/List.go: -------------------------------------------------------------------------------- 1 | package DoubleLinked 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type Node struct { 9 | key interface{} 10 | value interface{} 11 | prev,next *Node 12 | } 13 | 14 | 15 | func (this Node) String() string { 16 | builder := strings.Builder{} 17 | fmt.Fprintf(&builder,"{%v : %v}",this.key,this.value) 18 | return builder.String() 19 | } 20 | 21 | func InitNode(key,value interface{}) *Node { 22 | return &Node{ 23 | key:key, 24 | value:value, 25 | } 26 | } 27 | 28 | type List struct { 29 | capacity int 30 | head *Node 31 | tail *Node 32 | size int 33 | } 34 | 35 | func InitList(capcity int) *List { 36 | return &List{ 37 | capacity:capcity, 38 | size:0, 39 | } 40 | } 41 | 42 | func (this *List) addHead (node *Node) *Node { 43 | if this.head == nil { 44 | this.head = node 45 | this.tail = node 46 | this.head.prev = nil 47 | this.tail.next = nil 48 | } else { 49 | node.next = this.head 50 | this.head.prev = node 51 | this.head = node 52 | this.head.prev = nil 53 | } 54 | this.size++ 55 | return node 56 | } 57 | 58 | func (this *List)addTail(node *Node) *Node { 59 | if this.tail == nil { 60 | this.tail = node 61 | this.head = node 62 | this.head.prev = nil 63 | this.tail.next = nil 64 | } else { 65 | this.tail.next = node 66 | node.prev = this.tail 67 | this.tail = node 68 | this.tail.next = nil 69 | } 70 | this.size++ 71 | return node 72 | } 73 | 74 | func (this *List) removeTail() *Node { 75 | if this.tail == nil { 76 | return nil 77 | } 78 | node := this.tail 79 | if node.prev != nil { 80 | this.tail = node.prev 81 | this.tail.next = nil 82 | } else { 83 | this.tail = nil 84 | this.head = nil 85 | } 86 | this.size-- 87 | return node 88 | } 89 | 90 | func (this *List) removeHead() *Node { 91 | if this.head == nil { 92 | return nil 93 | } 94 | node := this.head 95 | if node.next != nil { 96 | this.head = node.next 97 | this.head.prev = nil 98 | } else { 99 | this.tail = nil 100 | this.head = nil 101 | } 102 | this.size-- 103 | return node 104 | } 105 | 106 | func (this *List)remove(node *Node) *Node { 107 | // 如果node==nil,默认删除尾节点 108 | if node == nil { 109 | node = this.tail 110 | } 111 | if node == this.tail { 112 | this.removeTail() 113 | } else if node == this.head { 114 | this.removeHead() 115 | } else { 116 | node.next.prev = node.prev 117 | node.prev.next = node.next 118 | this.size-- 119 | } 120 | return node 121 | } 122 | // 弹出头结点 123 | func (this *List)Pop() *Node { 124 | return this.removeHead() 125 | } 126 | 127 | // 添加节点,默认添加到尾部 128 | func (this *List)Append(node *Node) *Node { 129 | return this.addTail(node) 130 | } 131 | func (this *List)AppendToHead(node *Node) *Node { 132 | return this.addHead(node) 133 | } 134 | 135 | func (this *List)Remove(node *Node) *Node { 136 | return this.remove(node) 137 | } 138 | 139 | func (this *List)String() string { 140 | p := this.head 141 | builder := strings.Builder{} 142 | for p != nil { 143 | fmt.Fprintf(&builder,"%s",p) 144 | p = p.next 145 | if p != nil { 146 | fmt.Fprintf(&builder,"=>") 147 | } 148 | } 149 | return builder.String() 150 | } -------------------------------------------------------------------------------- /DoubleLinked/test.txt: -------------------------------------------------------------------------------- 1 | 2 3 2 1 5 2 4 5 3 2 5 2 -------------------------------------------------------------------------------- /Graph_algo/.idea/Graph_algo.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Graph_algo/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /Graph_algo/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Graph_algo/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Graph_algo/Adj/Hash.go: -------------------------------------------------------------------------------- 1 | package Adj 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | // 使用哈希存储表示无向图 11 | type Hash struct { 12 | v int 13 | e int 14 | adj map[int][]int 15 | } 16 | 17 | func (hash *Hash) E() int { 18 | return hash.e 19 | } 20 | 21 | func (hash *Hash) SetE(e int) { 22 | hash.e = e 23 | } 24 | 25 | func (hash *Hash) V() int { 26 | return hash.v 27 | } 28 | 29 | func (hash *Hash) SetV(v int) { 30 | hash.v = v 31 | } 32 | 33 | // 从文件中读取并创建一个无向图 34 | func (hash *Hash) ReadFromFile(filename string) (err error) { 35 | var ( 36 | file *os.File 37 | v int 38 | e int 39 | ) 40 | if file, err = os.Open(filename); err != nil { 41 | return 42 | } 43 | defer file.Close() 44 | // golang按照列读取每行数据的方法 45 | if _, err = fmt.Fscanln(file, &v, &e); err != nil { 46 | return 47 | } 48 | if v < 0 || e < 0 { 49 | return errors.New("图的顶点或边数不能小于0!") 50 | } 51 | hash.v = v 52 | hash.e = e 53 | 54 | // golang独特的建立二维数组的方法 55 | hash.adj = make(map[int][]int, v) 56 | for i := 0; i < v; i++ { 57 | hash.adj[i] = make([]int, 0) 58 | } 59 | for { 60 | if _, err = fmt.Fscanln(file, &v, &e); err != nil { 61 | return 62 | } 63 | if err = hash.ValidateVertex(v); err != nil { 64 | return 65 | } 66 | if err = hash.ValidateVertex(e); err != nil { 67 | return 68 | } 69 | if value, ok := hash.adj[v]; ok && Find(value, e) != -1 { 70 | err = errors.New("Parallel edges are detected!") 71 | return 72 | } 73 | if v == e { 74 | err = errors.New("Self Loop is detected!") 75 | return 76 | } 77 | hash.adj[v] = append(hash.adj[v], e) 78 | hash.adj[e] = append(hash.adj[e], v) 79 | } 80 | return 81 | } 82 | 83 | // 验证是否越界 84 | func (hash *Hash) ValidateVertex(check int) (err error) { 85 | if check >= hash.v || check < 0 { 86 | err = errors.New("vertex is invalid") 87 | } 88 | return 89 | } 90 | 91 | // 检测一条边是否联通 92 | func (hash *Hash) HasEdge(v int, e int) bool { 93 | if err := hash.ValidateVertex(v); err != nil { 94 | panic(err) 95 | } 96 | if err := hash.ValidateVertex(e); err != nil { 97 | panic(err) 98 | } 99 | if value, ok := hash.adj[v]; ok && Find(value, e) != -1 { 100 | return true 101 | } 102 | return false 103 | } 104 | 105 | // 根据一个顶点返回所有的联通边 106 | func (hash *Hash) LinkedVertex(v int) (edgeArr []int) { 107 | edgeArr = make([]int, 0) 108 | if err := hash.ValidateVertex(v); err != nil { 109 | panic(err) 110 | } 111 | for _, value := range hash.adj[v] { 112 | edgeArr = append(edgeArr, value) 113 | } 114 | return 115 | } 116 | func Find(a []int,v int)(index int){ 117 | for index,_ = range a { 118 | if v == a[index]{ 119 | return 120 | } 121 | } 122 | return -1 123 | } 124 | 125 | // 构造打印方法 126 | func (hash *Hash) String() string { 127 | var ( 128 | builder strings.Builder 129 | index int 130 | value []int 131 | //j int 132 | finalValue int 133 | ) 134 | fmt.Fprintf(&builder, "V = %d, E = %d", hash.v, hash.e) 135 | // golang独特的遍历二维数组的方法 136 | for index, value = range hash.adj { 137 | fmt.Fprintf(&builder, "\n%d : ", index) 138 | for _, finalValue = range value { 139 | fmt.Fprintf(&builder, "%d ", finalValue) 140 | } 141 | } 142 | return builder.String() 143 | } 144 | 145 | // 计算一个节点的度数 146 | func (hash *Hash) Degree(v int) (res int) { 147 | return len(hash.LinkedVertex(v)) 148 | } 149 | -------------------------------------------------------------------------------- /Graph_algo/Adj/Matrix.go: -------------------------------------------------------------------------------- 1 | package Adj 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | // 使用邻接矩阵表示无向图 11 | type Matrix struct { 12 | v int 13 | e int 14 | adj [][]int 15 | } 16 | 17 | func (matrix *Matrix) E() int { 18 | return matrix.e 19 | } 20 | 21 | func (matrix *Matrix) SetE(e int) { 22 | matrix.e = e 23 | } 24 | 25 | func (matrix *Matrix) V() int { 26 | return matrix.v 27 | } 28 | 29 | func (matrix *Matrix) SetV(v int) { 30 | matrix.v = v 31 | } 32 | 33 | // 从文件中读取并创建一个无向图 34 | func (matrix *Matrix) ReadFromFile(filename string) (err error) { 35 | var ( 36 | file *os.File 37 | v int 38 | e int 39 | ) 40 | if file, err = os.Open(filename); err != nil { 41 | return 42 | } 43 | defer file.Close() 44 | // golang按照列读取每行数据的方法 45 | if _, err = fmt.Fscanln(file, &v, &e); err != nil { 46 | return 47 | } 48 | if v < 0 || e < 0 { 49 | return errors.New("图的顶点或边数不能小于0!") 50 | } 51 | matrix.v = v 52 | matrix.e = e 53 | 54 | // golang独特的建立二维数组的方法 55 | matrix.adj = make([][]int, v) 56 | for i := 0; i < v; i++ { 57 | matrix.adj[i] = make([]int, v) 58 | } 59 | for { 60 | if _, err = fmt.Fscanln(file, &v, &e); err != nil { 61 | return 62 | } 63 | if err = matrix.validateVertex(v); err != nil { 64 | return 65 | } 66 | if err = matrix.validateVertex(e); err != nil { 67 | return 68 | } 69 | if matrix.adj[v][e] == 1 { 70 | err = errors.New("Parallel edges are detected!") 71 | return 72 | } 73 | if v == e { 74 | err = errors.New("Self Loop is detected!") 75 | return 76 | } 77 | matrix.adj[v][e] = 1 78 | matrix.adj[e][v] = 1 79 | } 80 | return 81 | } 82 | 83 | // 验证是否越界 84 | func (matrix *Matrix) validateVertex(check int) (err error) { 85 | if check >= matrix.v || check < 0 { 86 | err = errors.New("vertex is invalid") 87 | } 88 | return 89 | } 90 | 91 | // 检测一条边是否联通 92 | func (matrix *Matrix) HasEdge(v int, e int) bool { 93 | if err := matrix.validateVertex(v); err != nil { 94 | panic(err) 95 | } 96 | if err := matrix.validateVertex(e); err != nil { 97 | panic(err) 98 | } 99 | return matrix.adj[v][e] == 1 100 | } 101 | 102 | // 根据一个顶点返回所有的联通边 103 | func (matrix *Matrix) LinkedVertex(v int) (edgearr []int) { 104 | edgearr = make([]int, 0) 105 | for i := 0; i < matrix.v; i++ { 106 | if matrix.adj[v][i] == 1 { 107 | edgearr = append(edgearr, i) 108 | } 109 | } 110 | return 111 | } 112 | 113 | // 构造打印方法 114 | func (matrix *Matrix) String() string { 115 | var ( 116 | builder strings.Builder 117 | //index int 118 | value []int 119 | //j int 120 | finalValue int 121 | ) 122 | fmt.Fprintf(&builder, "V = %d, E = %d", matrix.v, matrix.e) 123 | // golang独特的遍历二维数组的方法 124 | for _, value = range matrix.adj { 125 | fmt.Fprintf(&builder, "\n") 126 | for _, finalValue = range value { 127 | fmt.Fprintf(&builder, "%d ", finalValue) 128 | } 129 | } 130 | return builder.String() 131 | } 132 | 133 | // 计算一个节点的度数 134 | func (matrix *Matrix) Degree(v int) (res int) { 135 | return len(matrix.LinkedVertex(v)) 136 | } 137 | -------------------------------------------------------------------------------- /Graph_algo/Adj/Matrix_test.go: -------------------------------------------------------------------------------- 1 | package Adj 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestMatrix_Degree(t *testing.T) { 9 | m := &Matrix{} 10 | m.ReadFromFile("../g.txt") 11 | fmt.Println(m) 12 | } 13 | -------------------------------------------------------------------------------- /Graph_algo/Adj/Table.go: -------------------------------------------------------------------------------- 1 | package Adj 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | // 使用邻接表表示无向图 10 | type Table struct { 11 | v int 12 | e int 13 | adj [][]int 14 | } 15 | 16 | func (table *Table) E() int { 17 | return table.e 18 | } 19 | 20 | func (table *Table) SetE(e int) { 21 | table.e = e 22 | } 23 | 24 | func (table *Table) V() int { 25 | return table.v 26 | } 27 | 28 | func (table *Table) SetV(v int) { 29 | table.v = v 30 | } 31 | 32 | // 从文件中读取并创建一个无向图 33 | func (table *Table) ReadFromFile (filename string)(err error){ 34 | var ( 35 | file *os.File 36 | v int 37 | e int 38 | ) 39 | if file,err = os.Open(filename);err!=nil{ 40 | return 41 | } 42 | defer file.Close() 43 | // golang按照列读取每行数据的方法 44 | if _, err = fmt.Fscanln(file, &v, &e);err!=nil{ 45 | return 46 | } 47 | if v < 0 || e < 0 { 48 | return errors.New("图的顶点或边数不能小于0!") 49 | } 50 | table.v = v 51 | table.e = e 52 | 53 | // golang独特的建立二维数组的方法 54 | table.adj = make([][]int,v) 55 | for i:=0;i=table.v || check<0{ 85 | err = errors.New("vertex is invalid") 86 | } 87 | return 88 | } 89 | 90 | // 检测一条边是否联通 91 | func (table *Table) HasEdge(v int,e int) bool{ 92 | if err := table.validateVertex(v);err!=nil{ 93 | panic(err) 94 | } 95 | if err := table.validateVertex(e);err!=nil{ 96 | panic(err) 97 | } 98 | return Find(table.adj[v],e)!=-1 99 | } 100 | // 根据一个顶点返回所有的联通边 101 | func (table *Table) LinkedVertex(v int) []int{ 102 | if err := table.validateVertex(v);err!=nil{ 103 | panic(err) 104 | } 105 | return table.adj[v] 106 | } 107 | // 构造打印方法 108 | func (table *Table) String() string { 109 | var ( 110 | builder strings.Builder 111 | index int 112 | value []int 113 | //j int 114 | finalValue int 115 | ) 116 | fmt.Fprintf(&builder, "V = %d, E = %d",table.v,table.e) 117 | // golang独特的遍历二维数组的方法 118 | for index,value = range table.adj { 119 | fmt.Fprintf(&builder,"\n%d : ",index) 120 | for _,finalValue = range value { 121 | fmt.Fprintf(&builder, "%d ",finalValue) 122 | } 123 | } 124 | return builder.String() 125 | } 126 | // 计算一个节点的度数 127 | func (table *Table) Degree(v int)(res int){ 128 | return len(table.LinkedVertex(v)) 129 | } 130 | 131 | func Find(a []int,v int)(index int){ 132 | for index,_ = range a { 133 | if v == a[index]{ 134 | return 135 | } 136 | } 137 | return -1 138 | } -------------------------------------------------------------------------------- /Graph_algo/Adj/Table_test.go: -------------------------------------------------------------------------------- 1 | package Adj 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestFind(t *testing.T) { 9 | m := &Table{} 10 | m.ReadFromFile("../g.txt") 11 | fmt.Println(m) 12 | } 13 | -------------------------------------------------------------------------------- /Graph_algo/BFS/traverse.go: -------------------------------------------------------------------------------- 1 | package BFS 2 | 3 | import ( 4 | "algo/Graph_algo/Adj" 5 | "fmt" 6 | ) 7 | 8 | // 广度优先遍历取所有节点 9 | func Traverse(hash *Adj.Hash, start int) (order []int) { 10 | var ( 11 | visited []bool 12 | que []int 13 | temp int 14 | ) 15 | visited = make([]bool, hash.V()) 16 | if err := hash.ValidateVertex(start); err != nil { 17 | panic(err) 18 | } 19 | que = append(que, start) 20 | visited[start] = true 21 | // 最外层循环保证图中有多个联通分量也可以访问到所有节点 22 | for i := 0; i < hash.V(); i++ { 23 | if !visited[i] { 24 | que = append(que, i) 25 | visited[i] = true 26 | } 27 | for len(que) > 0 { 28 | temp = que[0] 29 | order = append(order, temp) 30 | que = que[1:] 31 | for _, v := range hash.LinkedVertex(temp) { 32 | if !visited[v] { 33 | que = append(que, v) 34 | visited[v] = true 35 | } 36 | } 37 | } 38 | } 39 | fmt.Println(visited) 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /Graph_algo/DFS/CC.go: -------------------------------------------------------------------------------- 1 | package DFS 2 | 3 | import ( 4 | "algo/Graph_algo/Adj" 5 | "fmt" 6 | ) 7 | // 深度优先遍历一张图,并且找到所有连通分量(Connect Component) 8 | type CC struct { 9 | graph *Adj.Hash 10 | visited []int 11 | cccount int 12 | } 13 | 14 | func (C *CC) Cccount() int { 15 | for _,v := range C.visited { 16 | fmt.Printf("%d ",v) 17 | } 18 | fmt.Printf("\n") 19 | return C.cccount 20 | } 21 | 22 | func (C *CC) Init(graph *Adj.Hash){ 23 | C.graph = graph 24 | C.visited = make([]int,C.graph.V()) 25 | for i,_ := range C.visited { 26 | C.visited[i]= -1 27 | } 28 | for i:=0;i= 0 && x < R && y >= 0 && y < C 22 | } 23 | queue := make([]int,0) 24 | // 将二维数组映射到一维中, 则第一个点为0 25 | queue = append(queue,0) 26 | visited[0][0] = true 27 | dis[0][0] = 1 28 | for len(queue) > 0 { 29 | cur := queue[0] 30 | queue = queue[1:] 31 | // 一维长度转二维坐标 32 | curX,curY := cur/C, cur%C 33 | for i:=0;i<8;i++ { 34 | newX,newY := curX + dirs[i][0], curY + dirs[i][1] 35 | if InArea(newX, newY) && !visited[newX][newY] && 36 | grid[newX][newY] == 0{ 37 | queue = append(queue,newX*C + newY) 38 | visited[newX][newY] = true 39 | dis[newX][newY] = dis[curX][curY] + 1 40 | 41 | if newX == R-1 && newY == C-1 { 42 | return dis[newX][newY] 43 | } 44 | } 45 | } 46 | } 47 | return -1 48 | } 49 | 50 | 51 | -------------------------------------------------------------------------------- /Graph_algo/leetcode/1091_test.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestMax(t *testing.T) { 9 | test := [][]int{{0,0,0},{0,1,0},{0,0,0}} 10 | fmt.Println(shortestPathBinaryMatrix(test)) 11 | cur := "0000" 12 | var curs []byte 13 | curs = []byte(cur) 14 | next := make([]string,0) 15 | for i,v := range curs { 16 | curs[i] = ( v - '0' + 1 )%10 + '0' 17 | next = append(next,string(curs)) 18 | 19 | curs[i] = v 20 | curs[i] = (v - '0' + 9) % 10 + '0' 21 | next = append(next,string(curs)) 22 | curs[i] = v 23 | 24 | } 25 | fmt.Println(next) 26 | } 27 | -------------------------------------------------------------------------------- /Graph_algo/leetcode/200.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | // 统计岛屿个数 3 | func numIslands(grid [][]byte) int { 4 | dirs := [4][2]int {{-1,0},{0,1},{1,0},{0,-1}} 5 | 6 | // 如果二维数组不存在,直接返回 7 | if len(grid) == 0 { 8 | return 0 9 | } 10 | r := len(grid) 11 | if r == 0 { 12 | return 0 13 | } 14 | c := len(grid[0]) 15 | if c == 0 { 16 | return 0 17 | } 18 | 19 | // 判断一点是否在可选范围 20 | inArea := func(x,y int) bool { 21 | return x >= 0 && x < r && y >= 0 && y < c 22 | } 23 | 24 | // 开辟布尔型空间,和矩阵一一对应 25 | visited := make([][]bool,r) 26 | for i := 0; i < r; i++ { 27 | visited[i] = make([]bool,c) 28 | } 29 | res := 0 30 | var dfs func(x,y int) int 31 | dfs = func(x,y int) int { 32 | visited[x][y] = true 33 | tmp := 1 34 | for i := 0; i < 4; i++ { 35 | newX,newY := x + dirs[i][0], y + dirs[i][1] 36 | // 如果新点在矩阵中,且未被遍历过,且他是陆地,就可继续深度遍历 37 | if inArea(newX,newY) && !visited[newX][newY] && grid[newX][newY] == '1' { 38 | dfs(newX,newY) 39 | } 40 | } 41 | return tmp 42 | } 43 | for i := 0; i < r; i++ { 44 | for j := 0; j < c; j++ { 45 | if !visited[i][j] && grid[i][j] == '1' { 46 | res += dfs(i,j) 47 | } 48 | } 49 | } 50 | return res 51 | } 52 | -------------------------------------------------------------------------------- /Graph_algo/leetcode/4LWater.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | // 如果你有无穷多的水,一个3 公升的提捅,一个5 公升的提捅,两只提捅形状上下都不均 匀,问你如何才能准确称出4 公升的水? 3 | func FindPath(target int) []int { 4 | queue := make([]int,0) 5 | visited := make([]bool,100) 6 | pre := make([]int,100) 7 | var result func(end int) []int 8 | result = func(end int) []int { 9 | if end == -1 { 10 | return nil 11 | } 12 | res := make([]int,0) 13 | cur := end 14 | for cur != 0 { 15 | res = append(res,cur) 16 | cur = pre[cur] 17 | } 18 | res = append(res, 0) 19 | reverse(res) 20 | return res 21 | } 22 | 23 | queue = append(queue, 0) 24 | visited[0] = true 25 | for len(queue) > 0 { 26 | cur := queue[0] 27 | queue = queue[1:] 28 | curX,curY := cur/10, cur%10 29 | nexts := make([]int,0) 30 | // TODO: 找到next的六种情况 31 | nexts = append(nexts, 5*10 + curY) 32 | nexts = append(nexts, curX*10 + 3) 33 | nexts = append(nexts, 0*10 +curY) 34 | nexts = append(nexts, curX*10+0) 35 | x := min(3-curY,curX) 36 | nexts = append(nexts, (curX-x)*10+curY+x) 37 | y := min(5-curX,curY) 38 | nexts = append(nexts, (curX+y)*10+curY-y) 39 | for _,v := range nexts { 40 | if !visited[v] { 41 | queue = append(queue,v) 42 | pre[v] = cur 43 | visited[v] = true 44 | 45 | if v /10 == target || v%10 == target { 46 | return result(v) 47 | } 48 | } 49 | } 50 | } 51 | return nil 52 | } 53 | 54 | func min(x,y int) int { 55 | if x= 0 && x < r && y >= 0 && y < c 22 | } 23 | // 构造一个图的邻接表 24 | constructGraph := func() map[int][]int { 25 | g := make(map[int][]int) 26 | for v := 0; v < r*c; v++ { 27 | x,y := v/c , v%c 28 | if grid[x][y] == 1 { 29 | for d := 0; d < 4; d++ { 30 | newX := x + dirs[d][0] 31 | newY := y + dirs[d][1] 32 | if inArea(newX, newY) && grid[newX][newY] == 1 { 33 | next := newX * c + newY 34 | g[v] = append(g[v],next) 35 | g[next] = append(g[next],v) 36 | } 37 | } 38 | } 39 | } 40 | return g 41 | } 42 | 43 | g := constructGraph() 44 | res := 0 45 | visited := make([]bool,r*c) 46 | var dfs func(v int) int 47 | dfs = func(v int) int { 48 | visited[v] = true 49 | tmp := 1 50 | for _,w := range g[v] { 51 | if !visited[w] { 52 | tmp += dfs(w) 53 | } 54 | } 55 | return tmp 56 | } 57 | for v := 0; v < r*c; v++ { 58 | x,y := v/c, v%c 59 | if !visited[v] && grid[x][y] == 1 { 60 | res = max(res,dfs(v)) 61 | } 62 | } 63 | return res 64 | } 65 | 66 | func max (x,y int) int { 67 | if x > y { 68 | return x 69 | } 70 | return y 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /Graph_algo/leetcode/695_2.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | 3 | // LeetCode695第二种解法,就地解决 4 | 5 | func maxAreaOfIsland2(grid [][]int) int { 6 | dirs := [4][2]int {{-1,0},{0,1},{1,0},{0,-1}} 7 | 8 | // 如果二维数组不存在,直接返回 9 | if len(grid) == 0 { 10 | return 0 11 | } 12 | r := len(grid) 13 | if r == 0 { 14 | return 0 15 | } 16 | c := len(grid[0]) 17 | if c == 0 { 18 | return 0 19 | } 20 | 21 | // 判断一点是否在可选范围 22 | inArea := func(x,y int) bool { 23 | return x >= 0 && x < r && y >= 0 && y < c 24 | } 25 | 26 | // 开辟布尔型空间,和矩阵一一对应 27 | visited := make([][]bool,r) 28 | for i := 0; i < r; i++ { 29 | visited[i] = make([]bool,c) 30 | } 31 | res := 0 32 | var dfs func(x,y int) int 33 | dfs = func(x,y int) int { 34 | visited[x][y] = true 35 | tmp := 1 36 | for i := 0; i < 4; i++ { 37 | newX,newY := x + dirs[i][0], y + dirs[i][1] 38 | // 如果新点在矩阵中,且未被遍历过,且他是陆地,就可继续深度遍历 39 | if inArea(newX,newY) && !visited[newX][newY] && grid[newX][newY] == 1 { 40 | tmp += dfs(newX,newY) 41 | } 42 | } 43 | return tmp 44 | } 45 | for i := 0; i < r; i++ { 46 | for j := 0; j < c; j++ { 47 | if !visited[i][j] && grid[i][j] == 1 { 48 | res = Max(res,dfs(i,j)) 49 | } 50 | } 51 | } 52 | return res 53 | } 54 | 55 | func Max (i, j int) int { 56 | if i > j { 57 | return i 58 | } 59 | return j 60 | } -------------------------------------------------------------------------------- /Graph_algo/leetcode/695_test.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test(t *testing.T) { 9 | 10 | test := [][]int{{1,1,0,1,1},{1,0,0,0,0},{0,0,0,0,1},{1,1,0,1,1}} 11 | fmt.Println(maxAreaOfIsland(test)) 12 | } 13 | -------------------------------------------------------------------------------- /Graph_algo/leetcode/752.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | 3 | func openLock(deadends []string, target string) int { 4 | deadSet := make(map[string]bool) 5 | 6 | for _,v := range deadends { 7 | deadSet[v] = true 8 | } 9 | 10 | if deadSet[target] == true { 11 | return -1 12 | } 13 | 14 | if deadSet["0000"] == true { 15 | return -1 16 | } 17 | 18 | if target == "0000" { 19 | return 0 20 | } 21 | 22 | // BFS 23 | queue := make([]string,0) 24 | queue = append(queue, "0000") 25 | visited := make(map[string]int) 26 | visited["0000"] = 0 27 | for len(queue) > 0 { 28 | cur := queue[0] 29 | queue = queue[1:] 30 | next := make([]string,0) 31 | var curs []byte 32 | curs = []byte(cur) 33 | // 将next字符串依次找到 34 | for i,v := range curs { 35 | curs[i] = ( v - '0' + 1 )%10 + '0' 36 | next = append(next,string(curs)) 37 | 38 | curs[i] = v 39 | curs[i] = (v - '0' + 9) % 10 + '0' 40 | next = append(next,string(curs)) 41 | curs[i] = v 42 | 43 | } 44 | // TODO:Next 45 | 46 | for _,v := range next { 47 | if _,ok := visited[v];!ok && !deadSet[v] { 48 | queue = append(queue,v) 49 | visited[v] = visited[cur] + 1 50 | if v == target { 51 | return visited[v] 52 | } 53 | } 54 | } 55 | } 56 | return -1 57 | } -------------------------------------------------------------------------------- /Graph_algo/leetcode/785.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | 3 | func isBipartite(graph [][]int) bool { 4 | v := len(graph) 5 | visited := make([]bool,v+1) 6 | colors := make([]int,v+1) 7 | for i:=0; i < v ; i++ { 8 | if !visited[i] { 9 | if !dfs(i, 0,graph,colors,visited) { 10 | return false 11 | } 12 | } 13 | } 14 | return true 15 | } 16 | 17 | // 从顶点v开始,判断图中是否有环 18 | func dfs(v int, color int, graph [][]int, colors []int,visited []bool) bool { 19 | visited[v] = true 20 | colors[v] = color 21 | for _, w := range graph[v] { 22 | if !visited[w] { 23 | if !dfs(w, 1-color,graph,colors,visited) { 24 | return false 25 | } 26 | } else if colors[w] == colors[v] { 27 | return false 28 | } 29 | } 30 | return true 31 | } -------------------------------------------------------------------------------- /Graph_algo/leetcode/shuffle.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | type Shuffle struct { 10 | N int 11 | // 格子数 12 | n int 13 | // 雷数 14 | m int 15 | } 16 | 17 | func (s Shuffle) Run () { 18 | // 记录在i位置中出现雷的频次 19 | rand.Seed(time.Now().Unix()) 20 | freq := make([]int,s.n) 21 | arr := make([]int,s.n) 22 | for i:=0;i 6 : ",single.Path(6)) 30 | //path = &search.Path{ 31 | // T:5, 32 | // SingleSource:single, 33 | //} 34 | //fmt.Println(path.Path()) 35 | //fmt.Println(path.Visited()) 36 | cycleDetection = new(search.Cycle) 37 | cycleDetection.Init(mar) 38 | fmt.Println(BFS.Traverse(mar, 0)) 39 | //fmt.Println(cycleDetection.HasCycle()) 40 | //Bip.Init(mar) 41 | //fmt.Println(Bip.IsBippart()) 42 | } 43 | -------------------------------------------------------------------------------- /Graph_algo/notBip.txt: -------------------------------------------------------------------------------- 1 | 4 6 2 | 0 1 3 | 0 2 4 | 0 3 5 | 1 2 6 | 1 3 7 | 2 3 8 | -------------------------------------------------------------------------------- /Graph_algo/search/BipartitionDetection.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import "algo/Graph_algo/Adj" 4 | // 验证一个图是否是二分图 5 | type BipartitionDetection struct { 6 | graph *Adj.Hash 7 | visited []bool 8 | color []int 9 | isBippart bool 10 | } 11 | 12 | func (C *BipartitionDetection) IsBippart() bool { 13 | return C.isBippart 14 | } 15 | 16 | func (C *BipartitionDetection) Init(graph *Adj.Hash) { 17 | 18 | C.graph = graph 19 | C.visited = make([]bool, C.graph.V()) 20 | C.color = make([]int, C.graph.V()) 21 | C.isBippart = true 22 | for i, _ := range C.color { 23 | C.color[i] = -1 24 | } 25 | for i := 0; i < C.graph.V(); i++ { 26 | if !C.visited[i] { 27 | if !C.Dfs(i, 0) { 28 | C.isBippart = false 29 | break 30 | } 31 | } 32 | } 33 | 34 | } 35 | 36 | // 从顶点v开始,判断图中是否有环 37 | func (C *BipartitionDetection) Dfs(v int, color int) bool { 38 | C.visited[v] = true 39 | C.color[v] = color 40 | for _, w := range C.graph.LinkedVertex(v) { 41 | if !C.visited[w] { 42 | if !C.Dfs(w, 1-color) { 43 | return false 44 | } 45 | } else if C.color[w] == C.color[v] { 46 | return false 47 | } 48 | } 49 | return true 50 | } 51 | -------------------------------------------------------------------------------- /Graph_algo/search/Cycle.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "algo/Graph_algo/Adj" 5 | ) 6 | // 验证一个图中是否存在一个环 7 | type Cycle struct { 8 | graph *Adj.Hash 9 | visited []bool 10 | hasCycle bool 11 | } 12 | 13 | func (C *Cycle) HasCycle() bool { 14 | return C.hasCycle 15 | } 16 | 17 | func (C *Cycle) Init(graph *Adj.Hash) { 18 | 19 | C.graph = graph 20 | C.hasCycle = false 21 | C.visited = make([]bool, C.graph.V()) 22 | for i := 0; i < C.graph.V(); i++ { 23 | if !C.visited[i] { 24 | if C.Dfs(i, i) { 25 | C.hasCycle = true 26 | break 27 | } 28 | } 29 | } 30 | 31 | } 32 | 33 | // 从顶点v开始,判断图中是否有环 34 | func (C *Cycle) Dfs(v int, parent int) bool { 35 | C.visited[v] = true 36 | for _, w := range C.graph.LinkedVertex(v) { 37 | if !C.visited[w] { 38 | if C.Dfs(w, v) { 39 | return true 40 | } 41 | } else if w != parent { 42 | return true 43 | } 44 | } 45 | return false 46 | } 47 | -------------------------------------------------------------------------------- /Graph_algo/search/Find.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | // 寻找单源路径 4 | type Path struct { 5 | *SingleSource 6 | T int 7 | } 8 | 9 | func (C *Path) Visited() []bool { 10 | return C.visited 11 | } 12 | 13 | func (C *Path) Dfs(v int, parent int) bool { 14 | C.visited[v] = true 15 | C.pre[v] = parent 16 | if v == C.T { 17 | return true 18 | } 19 | for _, w := range C.graph.LinkedVertex(v) { 20 | if !C.visited[w] { 21 | if C.Dfs(w, v) { 22 | return false 23 | } 24 | } 25 | } 26 | return false 27 | } 28 | 29 | func (C *Path) IsConnectedTo() bool { 30 | return C.visited[C.T] 31 | } 32 | 33 | func (C *Path) Path() (res []int) { 34 | if !C.IsConnectedTo() { 35 | return 36 | } 37 | cur := C.T 38 | for cur != C.s { 39 | res = append(res, cur) 40 | cur = C.pre[cur] 41 | } 42 | res = append(res, C.s) 43 | for i := 0; i < len(res)/2; i++ { 44 | res[i], res[len(res)-i-1] = res[len(res)-i-1], res[i] 45 | } 46 | return 47 | } 48 | -------------------------------------------------------------------------------- /Graph_algo/search/SingleSourcePath.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import "algo/Graph_algo/Adj" 4 | 5 | type SingleSource struct { 6 | graph *Adj.Hash 7 | visited []bool 8 | s int 9 | pre []int 10 | } 11 | 12 | func (C *SingleSource) Pre() []int { 13 | return C.pre 14 | } 15 | 16 | func (C *SingleSource) IsConnectedTo(t int) bool { 17 | if err := C.graph.ValidateVertex(t); err != nil { 18 | panic(err) 19 | } 20 | return C.visited[t] 21 | } 22 | func (C *SingleSource) Path(t int) (res []int) { 23 | if !C.IsConnectedTo(t) { 24 | return 25 | } 26 | cur := t 27 | for cur != C.s { 28 | res = append(res, cur) 29 | cur = C.pre[cur] 30 | } 31 | res = append(res, C.s) 32 | for i := 0; i < len(res)/2; i++ { 33 | res[i], res[len(res)-i-1] = res[len(res)-i-1], res[i] 34 | } 35 | return 36 | } 37 | 38 | func (C *SingleSource) Init(graph *Adj.Hash, s int) { 39 | 40 | C.graph = graph 41 | if err := C.graph.ValidateVertex(s); err != nil { 42 | panic(err) 43 | } 44 | C.visited = make([]bool, C.graph.V()) 45 | C.pre = make([]int, C.graph.V()) 46 | for i, _ := range C.pre { 47 | C.pre[i] = -1 48 | } 49 | C.s = s 50 | C.Dfs(s, s) 51 | } 52 | 53 | func (C *SingleSource) Dfs(v int, parent int) { 54 | C.visited[v] = true 55 | C.pre[v] = parent 56 | for _, w := range C.graph.LinkedVertex(v) { 57 | if !C.visited[w] { 58 | C.Dfs(w, v) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Heap/Arrar_test.go: -------------------------------------------------------------------------------- 1 | package Heap 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "math/rand" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | func TestMaxHeap(t *testing.T) { 12 | n := 1000000 13 | ArrHeap := MaxHeap{ 14 | arr:make([]int,0), 15 | } 16 | start := time.Now() 17 | for i:=0; i < n; i++ { 18 | ArrHeap.Add(rand.Intn(math.MaxInt32)) 19 | } 20 | end := time.Now() 21 | // 生成一个一百万空间的数组把堆装回去,如果我们的算法无误,那么数组将是有序的 22 | 23 | test_arr := make([]int,1000000) 24 | for i:=0; i=0;i-- { 12 | heap.siftDown(i) 13 | } 14 | return heap 15 | } 16 | // 返回堆中元素个数 17 | func(heap *MaxHeap) Size() int { 18 | return len(heap.arr) 19 | } 20 | // 返回堆是否为空 21 | func(heap *MaxHeap) IsEmpty () bool { 22 | if len(heap.arr) == 0 { 23 | return true 24 | } 25 | return false 26 | } 27 | // 计算父节点 28 | func(heap *MaxHeap) parent (index int) int { 29 | if index==0 { 30 | panic("0节点没有父亲节点") 31 | } 32 | return (index-1)/2 33 | } 34 | // 计算左孩子索引 35 | func(heap *MaxHeap) leftChild(index int) int { 36 | return index*2+1 37 | } 38 | // 计算右孩子索引 39 | func(heap *MaxHeap) rightChild(index int) int { 40 | return index*2+2 41 | } 42 | // 增加元素 43 | func (heap *MaxHeap)Add(e int) { 44 | heap.arr = append(heap.arr,e) 45 | heap.siftUp(heap.Size()-1) 46 | } 47 | // 数据上浮 48 | func (heap *MaxHeap) siftUp(size int) { 49 | 50 | for size > 0 && heap.arr[heap.parent(size)] < heap.arr[size]{ 51 | heap.arr[heap.parent(size)],heap.arr[size]=heap.arr[size],heap.arr[heap.parent(size)] 52 | size = heap.parent(size) 53 | } 54 | } 55 | // 取出堆中最大的元素,并且替换成元素e 56 | func (heap *MaxHeap) Replace(e int) int { 57 | ret := heap.FindMax() 58 | heap.arr[0] = e 59 | heap.siftDown(0) 60 | return ret 61 | } 62 | // 删除最大元素 63 | func(heap *MaxHeap) RemoveMax() int { 64 | var ret int = heap.FindMax() 65 | heap.arr[heap.Size()-1],heap.arr[heap.Size()-1] = heap.arr[heap.Size()-1],heap.arr[heap.Size()-1] 66 | heap.arr = heap.arr[:heap.Size()-1] 67 | heap.siftDown(0) 68 | 69 | return ret 70 | } 71 | // 数据下沉 72 | func (heap *MaxHeap) siftDown(index int) { 73 | var ( 74 | j int 75 | ) 76 | for heap.leftChild(index) < heap.Size() { 77 | j = heap.leftChild(index) 78 | // 先判断右孩子的索引是否越界,如果不越界继续判断左右孩子哪个大 79 | if j+1 < heap.Size() && heap.arr[j+1] > heap.arr[j] { 80 | // 此时arr[j]将是左孩子和右孩子中最大的那个值 81 | j = heap.rightChild(index) 82 | } 83 | if heap.arr[index] >= heap.arr[j] { 84 | break 85 | } else { 86 | heap.arr[index],heap.arr[j]=heap.arr[j],heap.arr[index] 87 | index = j 88 | } 89 | } 90 | } 91 | 92 | func(heap *MaxHeap) FindMax() int { 93 | if heap.Size() == 0 { 94 | panic("堆是空的,不能查询了") 95 | } 96 | return heap.arr[0] 97 | } 98 | -------------------------------------------------------------------------------- /Heap/PriorityQueue.go: -------------------------------------------------------------------------------- 1 | package Heap 2 | 3 | type Queue interface { 4 | Enqueue(e int) 5 | Dequeue() int 6 | GetFront() int 7 | Size() int 8 | IsEmpty() bool 9 | } 10 | 11 | type PriorityQueue struct { 12 | heap *MaxHeap 13 | } 14 | 15 | func (this *PriorityQueue) Enqueue(e int) { 16 | this.heap.Add(e) 17 | } 18 | 19 | func (this *PriorityQueue) Dequeue() int { 20 | return this.heap.RemoveMax() 21 | } 22 | 23 | func (this *PriorityQueue) GetFront() int { 24 | return this.heap.FindMax() 25 | } 26 | func (this *PriorityQueue) Size() int { 27 | return this.heap.Size() 28 | } 29 | 30 | func (this *PriorityQueue) IsEmpty() bool { 31 | return this.heap.IsEmpty() 32 | } 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Administrator 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Linked/1.1 Reverse.go: -------------------------------------------------------------------------------- 1 | package Linked 2 | 3 | import "fmt" 4 | 5 | func (this *List)Reverse() { 6 | var pre *Node 7 | var cur *Node 8 | next := this.Head().Next 9 | 10 | for next != nil { 11 | cur = next.Next 12 | next.Next = pre 13 | pre = next 14 | next = cur 15 | } 16 | this.Head().Next = pre 17 | } 18 | 19 | func recursiveReverse(node *Node) *Node { 20 | if node == nil || node.Next == nil { 21 | return node 22 | } 23 | newHead := recursiveReverse(node.Next) 24 | node.Next.Next = node 25 | node.Next = nil 26 | return newHead 27 | } 28 | 29 | func (this *List) RecursiveReverse() { 30 | firstNode := this.Head().Next 31 | newHead := recursiveReverse(firstNode) 32 | this.Head().Next = newHead 33 | } 34 | 35 | func (this *List) InsertReverse () { 36 | if this.Head() == nil || this.Head().Next == nil{ 37 | return 38 | } 39 | var cur *Node //当前节点 40 | var next *Node //后继节点 41 | cur = this.Head().Next.Next 42 | // 设置链表第一个节点为尾节点 43 | this.Head().Next.Next = nil 44 | // 把遍历到的节点插入到头结点的后面 45 | for cur != nil { 46 | next = cur.Next 47 | cur.Next = this.Head().Next 48 | this.Head().Next = cur 49 | cur = next 50 | } 51 | } 52 | 53 | func (this List)ReversePrint(node *Node) { 54 | if node == nil { 55 | return 56 | } 57 | this.ReversePrint(node.Next) 58 | fmt.Printf("%d ",node.E) 59 | } -------------------------------------------------------------------------------- /Linked/1.10 RemoveNode.go: -------------------------------------------------------------------------------- 1 | package Linked 2 | 3 | // 给定一个链表中一个节点的指针,让你删除这个节点 4 | func (this *List)RemoveNode(node *Node) bool { 5 | // 分析一下,我们如果想要删除一个节点,那么是需要找到这个节点的前驱的 6 | // 那么在这一题中,如果给的是尾节点,那么我们是没有办法删除的,但是如果不是尾节点的话 7 | // 我们可以采用这种取巧的方式删除这个节点 8 | // 1. 将该节点的后继节点的值赋值给它 9 | // 2. 将该节点的后继节点删除 10 | 11 | // 这里判断如果是空链表或者传入的是尾节点,那么我们就直接返回false 12 | if this.Head() == nil || this.Head().Next == nil||node.Next == nil{ 13 | return false 14 | } 15 | E := node.Next.E 16 | node.E = E 17 | node.Next = node.Next.Next 18 | return true 19 | } 20 | -------------------------------------------------------------------------------- /Linked/1.11 CheckIntersect.go: -------------------------------------------------------------------------------- 1 | package Linked 2 | // 第一种方法,首尾相接法,把两个链表首尾相接,如果有交叉,必成一个环,只需要用1.6做的寻找入口节点的方式就能找到结果 3 | // 时间复杂度O(n1+n2),空间复杂度O(n1) 4 | func (this *List)CheckIntersect(head1,head2 *Node) *Node { 5 | if head2 == nil || head2.Next == nil || head1 == nil || head1.Next == nil || head1 == head2 { 6 | return nil 7 | } 8 | findTail := func(node *Node) *Node { 9 | cur := node 10 | for cur.Next != nil { 11 | cur = cur.Next 12 | } 13 | return cur 14 | } 15 | tail := findTail(head1) 16 | tail.Next = head2.Next 17 | meet := this.FindLoop() 18 | entry := this.FindLoopEntryNode(meet) 19 | return entry 20 | } 21 | -------------------------------------------------------------------------------- /Linked/1.2 RemoveDup.go: -------------------------------------------------------------------------------- 1 | package Linked 2 | // 顺序式删除重复节点 3 | func (this *List) RemoveDup () { 4 | 5 | if this.Head() == nil || this.Head().Next == nil { 6 | return 7 | } 8 | // 外层循环,指向链表的第一个节点 9 | outerCur := this.Head().Next 10 | // 内层循环innerPre 和 innerCur 11 | var innerPre,innerCur *Node 12 | 13 | for ;outerCur != nil ; outerCur = outerCur.Next { 14 | for innerPre,innerCur = outerCur,outerCur.Next; innerCur != nil ; { 15 | if innerPre.E == innerCur.E { 16 | innerPre.Next = innerCur.Next 17 | innerCur = innerCur.Next 18 | } else { 19 | innerPre = innerCur 20 | innerCur = innerCur.Next 21 | } 22 | } 23 | } 24 | } 25 | 26 | func (this *List) RemoveDupRecursion (){ 27 | if this.Head() == nil { 28 | return 29 | } 30 | this.Head().Next = removeDupRecursionChild(this.Head().Next) 31 | } 32 | // 递归式删除重复节点 33 | func removeDupRecursionChild (node *Node) *Node { 34 | if node == nil || node.Next == nil { 35 | return node 36 | } 37 | var pointer *Node 38 | cur := node 39 | // 对以node.Next为首的子链表删除重复的节点 40 | node.Next = removeDupRecursionChild(node.Next) 41 | // 找出以node.Next为首的子链表中与node结点相同的结点并删除 42 | pointer = node.Next 43 | for pointer != nil { 44 | if node.E == pointer.E { 45 | cur.Next = pointer.Next 46 | pointer = pointer.Next 47 | } else { 48 | pointer = pointer.Next 49 | cur = cur.Next 50 | } 51 | } 52 | return node 53 | } 54 | 55 | // 用空间换时间 56 | func (this *List) RemoveDupWithMap () { 57 | if this.Head() == nil || this.Head().Next == nil { 58 | return 59 | } 60 | searchMap := make(map[int]*Node) 61 | pre := this.Head() 62 | cur := this.Head().Next 63 | for cur != nil { 64 | // 如果在哈希表中找到了这个数值,那就删除掉cur 65 | if _,ok := searchMap[cur.E]; ok { 66 | pre.Next = cur.Next 67 | cur = cur.Next 68 | } else { 69 | searchMap[cur.E] = cur 70 | cur = cur.Next 71 | pre = pre.Next 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Linked/1.3AddTwoList.go: -------------------------------------------------------------------------------- 1 | package Linked 2 | 3 | func AddTwoList(head1,head2 *Node) *List { 4 | newHead := InitList() 5 | p1 := head1.Next 6 | p2 := head2.Next 7 | carry := 0 8 | for p1 != nil || p2 != nil { 9 | if p1 == nil { 10 | newHead.AddLast(p2.E+ + carry) 11 | p2 = p2.Next 12 | } 13 | if p2 == nil { 14 | newHead.AddLast(p1.E + carry) 15 | p1 = p1.Next 16 | } 17 | temp := (p1.E + p2.E + carry )%10 18 | newHead.AddLast(temp) 19 | carry = (p1.E + p2.E + carry )/10 20 | p1 = p1.Next 21 | p2 = p2.Next 22 | } 23 | return newHead 24 | } 25 | -------------------------------------------------------------------------------- /Linked/1.4MiddleReverse.go: -------------------------------------------------------------------------------- 1 | package Linked 2 | 3 | func (this *List)findMidNode() *Node { 4 | if this.Head() == nil || this.Head().Next == nil { 5 | return nil 6 | } 7 | slow := this.Head() 8 | slowPre := this.Head() 9 | fast := this.Head() 10 | 11 | for fast != nil && fast.Next != nil { 12 | slowPre = slow 13 | slow = slow.Next 14 | fast = fast.Next.Next 15 | } 16 | slowPre.Next = nil 17 | return slow 18 | } 19 | 20 | func MidReverse(head *Node) *Node { 21 | if head == nil || head.Next == nil { 22 | return nil 23 | } 24 | 25 | var next *Node 26 | var pre *Node 27 | for head != nil { 28 | next = head.Next 29 | head.Next = pre 30 | pre = head 31 | head = next 32 | } 33 | return pre 34 | } 35 | 36 | func (this *List) Reorder () { 37 | if this.Head() == nil || this.Head() == nil { 38 | return 39 | } 40 | cur1 := this.Head().Next 41 | mid := this.findMidNode() 42 | cur2 := MidReverse(mid) 43 | var temp *Node 44 | // 合并链表 45 | for cur1.Next != nil { 46 | temp = cur1.Next 47 | cur1.Next = cur2 48 | cur1 = temp 49 | temp = cur2.Next 50 | cur2.Next = cur1 51 | cur2 = temp 52 | } 53 | cur1.Next = cur2 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Linked/1.5 FindLastK.go: -------------------------------------------------------------------------------- 1 | package Linked 2 | 3 | func (this *List) FindLastK(k int) *Node { 4 | if this.Head() == nil || this.Head().Next == nil { 5 | return nil 6 | } 7 | fast,slow := this.Head().Next,this.Head().Next 8 | var i int 9 | for i=0;i head2.Next.E { 17 | start = head2 18 | end = start2 19 | start2 = start2.Next 20 | } else { 21 | start = head1 22 | end = start1 23 | start1 = start1.Next 24 | } 25 | for start1 != nil && start2 != nil { 26 | if start1.E < start2.E { 27 | end.Next = start1 28 | end = start1 29 | start1 = start1.Next 30 | } else { 31 | end.Next = start2 32 | end = start2 33 | start2 = start2.Next 34 | } 35 | } 36 | // 如果start1取完了,那么把start2接到尾节点上,反之亦然 37 | if start1 == nil { 38 | end.Next = start2 39 | } 40 | if start2 == nil { 41 | end.Next = start1 42 | } 43 | return start 44 | } 45 | -------------------------------------------------------------------------------- /Linked/List_test.go: -------------------------------------------------------------------------------- 1 | package Linked 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | func TestList(t *testing.T) { 10 | list := InitList() 11 | list2 := InitList() 12 | for i:=0;i<5 ; i++ { 13 | list.AddFirst(i) 14 | list2.AddFirst(rand.Int()%17) 15 | } 16 | list2.Sort() 17 | list.Sort() 18 | fmt.Println(list,"\n",list2) 19 | fmt.Println(MergeTwoList(list2.Head(),list.Head())) 20 | fmt.Println(list) 21 | //for i:=9;i>0;i--{ 22 | // // if list.FindLastK(i) == nil { 23 | // // t.Error("超过链表可表示长度") 24 | // // } else { 25 | // // t.Log(list.FindLastK(i).E) 26 | // // } 27 | // //} 28 | // 29 | // //t.Log(list.Contains(4)) 30 | // //t.Log(list.Get(2)) 31 | // //list.AddIndex(2,666) 32 | // //t.Log(list) 33 | // //list.Reverse() 34 | // //t.Log(list) 35 | // //list.RecursiveReverse() 36 | // //t.Log(list) 37 | // //list.InsertReverse() 38 | // //t.Log(list) 39 | // //list.ReversePrint(list.Head().Next) 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Linked/README.md: -------------------------------------------------------------------------------- 1 | # 单向链表 2 | 3 | [TOC] 4 | 5 | 6 | 7 | ## 单向链表 8 | 9 | 单向链表属于链表的一种,也叫单链表,单向即是说它的链接方向是单向的,它由若干个节点组成,每个节点都包含下一个节点的指针。 10 | 11 | 数据结构: 12 | 13 | ```go 14 | type Node struct { 15 | E int 16 | Next *Node 17 | } 18 | 19 | type List struct { 20 | dummyHead *Node 21 | size int 22 | } 23 | 24 | func (l List) Head() *Node { 25 | return l.dummyHead 26 | } 27 | 28 | func (l List) Size() int { 29 | return l.size 30 | } 31 | ``` 32 | 33 | 34 | 35 | ## 单链表特点 36 | 37 | - 创建单链表时无需指定链表的长度,这个比起数组结构更加有优势,而数组纵使实现成动态数组也是需要指定一个更大的数组长度,而且要把原来的数组元素一个个复制到新数组中。 38 | - 单链表中的节点删除操作很方便,它可以直接改变指针指向来实现删除操作,而某些场景下数组的删除会导致移动剩下的元素。 39 | - 单链表中的元素访问需要通过顺序访问,即要通过遍历的方式来寻找元素,而数组则可以使用随机访问,这点算是单链表的缺点。 40 | 41 | ## 单链表创建 42 | 43 | 创建一个空链表,这里用到了虚拟头结点的方式 44 | 45 | ```go 46 | func initNode (e int) *Node { 47 | return &Node{ 48 | E:e, 49 | Next:nil, 50 | } 51 | } 52 | func InitList () *List { 53 | return &List{ 54 | dummyHead:initNode(0), 55 | size:0, 56 | } 57 | } 58 | ``` 59 | 60 | ## 链表的插入 61 | 62 | ```go 63 | // 在链表的第index索引个元素后插入元素,索引从0开始 64 | func (this *List) AddIndex (index,e int) { 65 | if index > this.size || index < 0 { 66 | panic("索引越界,不能插入了") 67 | } 68 | prev := this.dummyHead 69 | node := initNode(e) 70 | 71 | for i:=0;i this.size || index < 0 { 95 | panic("索引越界,不能删除") 96 | } 97 | prev := this.dummyHead 98 | for i:=0;i this.size || index < 0 { 134 | panic("索引越界,不能查询") 135 | } 136 | cur := this.dummyHead.Next 137 | for i:=0;i this.size || index < 0 { 156 | panic("索引越界,不能置入") 157 | } 158 | cur := this.dummyHead.Next 159 | for i:=0;i this.pending[this.ready[i]].submitTime { 75 | this.pending[this.ready[i]].finishTime = this.pending[this.ready[i-1]].finishTime + this.pending[this.ready[i]].runTime 76 | this.pending[this.ready[i]].waitTime = this.pending[this.ready[i-1]].finishTime - this.pending[this.ready[i]].submitTime 77 | } else { 78 | this.pending[this.ready[i]].finishTime = this.pending[this.ready[i]].runTime + this.pending[this.ready[i]].submitTime 79 | this.pending[this.ready[i]].waitTime = 0 80 | } 81 | } 82 | this.pending[this.ready[i]].GetColTime() 83 | this.pending[this.ready[i]].GetColTimeWithWeight() 84 | fmt.Printf("等待时间:%f\t周转时间:%f\t带权周转时间: %0.2f\n",this.pending[this.ready[i]].waitTime,this.pending[this.ready[i]].trTime,this.pending[this.ready[i]].wtrTime) 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /OSExam/FCFS_test.go: -------------------------------------------------------------------------------- 1 | package OSExam 2 | 3 | import "testing" 4 | 5 | func TestFCFS_FCFS(t *testing.T) { 6 | fcfs := FCFS{} 7 | fcfs.InitFromFile("test.txt") 8 | 9 | fcfs.FCFS() 10 | } -------------------------------------------------------------------------------- /OSExam/FP_test.go: -------------------------------------------------------------------------------- 1 | package OSExam 2 | 3 | import "testing" 4 | 5 | func TestFP_FP(t *testing.T) { 6 | fp := &FP{} 7 | fp.InitFromFile("test1.txt") 8 | fp.HPF() 9 | } 10 | -------------------------------------------------------------------------------- /OSExam/Process.go: -------------------------------------------------------------------------------- 1 | package OSExam 2 | 3 | // 周转时间 = 作业完成时间 - 作业提交时间 4 | 5 | type Process struct { 6 | finishTime float64 7 | submitTime float64 8 | startTime float64 9 | waitTime float64 10 | // 周转时间 11 | trTime float64 12 | wtrTime float64 13 | pid int 14 | // 这个是作业的实际运行时间 15 | runTime float64 16 | // 作业的优先级 17 | priority int 18 | // 标记是否访问过和是否到达 19 | reached bool 20 | visited bool 21 | } 22 | 23 | func (this *Process)GetColTime() { 24 | this.trTime = this.finishTime - this.submitTime 25 | } 26 | 27 | func (this *Process) GetColTimeWithWeight() { 28 | this.wtrTime = float64(this.trTime)/float64(this.runTime) 29 | } -------------------------------------------------------------------------------- /OSExam/SJF.go: -------------------------------------------------------------------------------- 1 | package OSExam 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "os" 7 | "time" 8 | ) 9 | 10 | type SJF struct { 11 | process []Process 12 | } 13 | 14 | func (this *SJF)InitFromFile(filename string) { 15 | var ( 16 | file *os.File 17 | id int 18 | sub float64 19 | run float64 20 | priority int 21 | err error 22 | ) 23 | if file,err = os.Open(filename);err != nil { 24 | panic(err) 25 | } 26 | defer file.Close() 27 | for { 28 | if _, err = fmt.Fscanln(file, &id, &sub,&run,&priority); err != nil { 29 | return 30 | } 31 | proce := Process{ 32 | pid:id, 33 | submitTime:sub, 34 | runTime:run, 35 | priority:priority, 36 | } 37 | this.process = append(this.process,proce) 38 | } 39 | return 40 | } 41 | 42 | func (this *SJF) FindNextSJF(finish float64) int { 43 | // p是已经到达且拥有最短运行时间的进程的下标 44 | // q是没有到达的进程中拥有最早到达时间的进程的下标 45 | var p,q int 46 | var minNeedTime,minReachTIme,minTime float64 47 | minNeedTime,minReachTIme,minTime = math.MaxInt32,math.MaxInt32,math.MaxInt32 48 | for i := 0; i < len(this.process); i++ { 49 | if !this.process[i].visited { 50 | // 第一种情况 51 | if this.process[i].submitTime <= finish && this.process[i].runTime <= minNeedTime { 52 | p = i 53 | minNeedTime = this.process[i].runTime 54 | } else if this.process[i].submitTime > finish && this.process[i].submitTime <= minReachTIme { 55 | if this.process[i].runTime < minTime { 56 | q = i 57 | minReachTIme = this.process[i].submitTime 58 | minTime = this.process[i].runTime 59 | } 60 | } 61 | } 62 | } 63 | if p != -1 { 64 | return p 65 | } 66 | return q 67 | } 68 | 69 | //短作业优先算法 70 | func (this *SJF) SJF () { 71 | var i int 72 | //总的等待时间 //总的周转时间 //总的带权周转时间 73 | var wrTime,trTime,wtrTime,finish float64 74 | finish = math.MaxInt32 //当前完成时间 75 | for i=0;i 0{ 25 | this.buildSegmentTree(0,0,len(this.data)-1) 26 | } 27 | } 28 | // 在treeIndex的位置创建表示区间[l……r]的线段树 29 | func (this *Tree) buildSegmentTree(treeIndex,l,r int) { 30 | if l == r { 31 | this.tree[treeIndex] = this.data[l] 32 | return 33 | } 34 | leftChild,rightChild := this.leftChild(treeIndex),this.rightChild(treeIndex) 35 | mid := l + (r-l)/2 36 | 37 | // 递归调用时创建从[l……mid]和[mid+1……r]两个区间的线段树 38 | this.buildSegmentTree(leftChild,l,mid) 39 | this.buildSegmentTree(rightChild,mid+1,r) 40 | 41 | // 在这里tree[index]的数据确定应该由具体的业务逻辑决定的 42 | this.tree[treeIndex] = this.merger(this.tree[leftChild],this.tree[rightChild]) 43 | } 44 | // 返回区间[l……R]的值 45 | func (this *Tree) QueryLR (QueryL,QueryR int) (res int,err error) { 46 | if QueryL<0 || QueryL>=len(this.data) || QueryR<0 || QueryR >=len(this.data) || QueryL>QueryR{ 47 | err = errors.New("index out of range!") 48 | } 49 | res = this.query(0,0,len(this.data)-1,QueryL,QueryR) 50 | return 51 | } 52 | func (this *Tree) query(treeIndex,l,r,queryL,queryR int)int { 53 | if l == queryL && r == queryR { 54 | return this.tree[treeIndex] 55 | } 56 | leftChild,rightChild := this.leftChild(treeIndex),this.rightChild(treeIndex) 57 | mid := l + (r - l)/2 58 | // 如果用户关心的区间跟左孩子完全没有关系,那么只需要查找右子树 59 | if queryL >= mid+1 { 60 | return this.query(rightChild,mid+1,r,queryL,queryR) 61 | } else if queryR <= mid { 62 | return this.query(leftChild,l,mid,queryL,queryR) 63 | } 64 | LeftRes := this.query(leftChild,l,mid,queryL,mid) 65 | RightRes := this.query(rightChild,mid+1,r,mid+1,queryR) 66 | return this.merger(LeftRes,RightRes) 67 | } 68 | func (this *Tree) Update (index,val int) { 69 | if index < 0 || index >= len(this.data) { 70 | panic("index out of range!") 71 | } 72 | this.data[index] = val 73 | this.update(0,0,len(this.data)-1,index,val) 74 | } 75 | // 递归更新区间,时间复杂度为O(logn) 76 | func (this *Tree) update (treeIndex,l,r,index,e int) { 77 | if l == r { 78 | this.tree[treeIndex] = e 79 | return 80 | } 81 | leftChild,rightChild := this.leftChild(treeIndex),this.rightChild(treeIndex) 82 | mid := l + (r-l)/2 83 | if index >= mid+1 { 84 | this.update(rightChild,mid+1,r,index,e) 85 | } else { 86 | this.update(leftChild,l,mid,index,e) 87 | } 88 | this.tree[treeIndex] = this.merger(this.tree[leftChild],this.tree[rightChild]) 89 | } 90 | func (this *Tree) GetSize () int { 91 | return len(this.data) 92 | } 93 | func (this *Tree) Get(index int) (res int,err error) { 94 | if index < 0 || index >= len(this.data) { 95 | err = errors.New("index out of range") 96 | } 97 | res = this.data[index] 98 | return 99 | } 100 | 101 | func (this *Tree) leftChild (k int) int { 102 | return 2*k+1 103 | } 104 | 105 | func (this *Tree) rightChild (k int) int { 106 | return 2*k+2 107 | } 108 | 109 | func (this *Tree) String() string { 110 | var builder strings.Builder 111 | builder.WriteString("[") 112 | for i:=0; ii;j-- { 10 | if arr[j] < arr[j-1] { 11 | arr[j],arr[j-1] = arr[j-1],arr[j] 12 | } 13 | } 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /Sorts/Bucket.go: -------------------------------------------------------------------------------- 1 | package Sorts 2 | 3 | func GradeSort(grade []int) { 4 | // 初始化出试卷范围[0-100] 5 | arr := make([]int,101) 6 | for _,v := range grade { 7 | // 每一个成绩装到对应的桶中 8 | arr[v]++ 9 | } 10 | // 把成绩装回去 11 | index := 0 12 | for i,v := range arr { 13 | // 桶空了就继续下一个 14 | if v == 0 { 15 | continue 16 | }else { 17 | v-- 18 | grade[index] = i 19 | index++ 20 | } 21 | } 22 | } 23 | 24 | func main() { 25 | grade := []int{4,66,66,67,55,55,66,99,100,4,67} 26 | } 27 | -------------------------------------------------------------------------------- /Sorts/Insert.go: -------------------------------------------------------------------------------- 1 | package Sorts 2 | 3 | func InsertSort (arr []int) { 4 | // 对于切片,他本身就是引用传递,所以可以用是否为nil判断 5 | if arr == nil { 6 | return 7 | } 8 | for i:=1; i tmp { 11 | for j>=1 && arr[j-1]>tmp { 12 | arr[j] = arr[j-1] 13 | j-- 14 | } 15 | } 16 | arr[j] = tmp 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sorts/Merge.go: -------------------------------------------------------------------------------- 1 | package Sorts 2 | 3 | // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 4 | func merge(arr,aux []int,l,mid,r int) { 5 | //* 如果你使用的是c++,这里特别提醒一下 6 | //* VS不支持动态长度数组, 即不能使用 T aux[r-l+1]的方式申请aux的空间 7 | //* 使用VS的同学, 请使用new的方式申请aux空间 8 | //* 使用new申请空间, 不要忘了在merge函数的最后, delete掉申请的空间:) 9 | aux = make([]int,r-l+1) 10 | for i:=l;i<=r;i++ { 11 | aux[i-l] = arr[i] 12 | } 13 | // 初始化,i指向左半部分的起始索引位置l,j指向mid+1 14 | i,j := l,mid+1 15 | for k:=l ; k<=r; k++ { 16 | // 如果左半部分元素已经处理完毕 17 | if i > mid { 18 | arr[k] = aux[j-l] 19 | j++ 20 | } else if j > r { 21 | arr[k] = aux[i-l] 22 | i++ 23 | } else if aux[i-l] < aux[j-l] { 24 | arr[k] = aux[i-l] 25 | i++ 26 | } else { 27 | arr[k] = aux[j-l] 28 | j++ 29 | } 30 | } 31 | } 32 | 33 | func MergeSort(arr []int,l,r int) { 34 | if l >= r { 35 | return 36 | } 37 | mid := (r+l)/2 38 | MergeSort(arr,l,mid) 39 | MergeSort(arr,mid+1,r) 40 | // 对于arr[mid] <= arr[mid+1]的情况,不进行merge 41 | // 对于近乎有序的数组非常有效,但是对于一般情况,有一定的性能损失。 42 | if arr[mid] > arr[mid+1] { 43 | var aux []int 44 | merge(arr,aux,l,mid,r) 45 | } 46 | } 47 | 48 | // 自底向上的归并排序 49 | func MergeSortBU(arr []int,n int) { 50 | aux := make([]int,n) 51 | // 一次性申请aux的空间,并将这个辅助空间以参数形式传递给完成归并排序的各个子函数 52 | for sz := 1 ; sz <= n; sz += sz { 53 | for i:=0;i arr[i+sz]{ 55 | merge(arr,aux,i,i+sz-1,min(i+sz+sz-1,n-1)) 56 | } 57 | } 58 | } 59 | } 60 | 61 | func min (a,b int ) int { 62 | if a < b { 63 | return a 64 | } 65 | return b 66 | } 67 | -------------------------------------------------------------------------------- /Sorts/Quick.go: -------------------------------------------------------------------------------- 1 | package Sorts 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | // 对arr[l...r]部分进行partition操作 9 | // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 10 | func partition (arr []int,l,r int) int { 11 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 12 | rand.Seed(time.Now().Unix()) 13 | randIndex := rand.Int()%(r-l+1)+l 14 | arr[l],arr[randIndex] = arr[randIndex],arr[l] 15 | 16 | v := arr[l] 17 | j := l 18 | for i := l+1; i<=r; i++ { 19 | if arr[i] < v { 20 | j++ 21 | arr[j],arr[i] = arr[i],arr[j] 22 | } 23 | } 24 | arr[l],arr[j] = arr[j],arr[l] 25 | return j 26 | } 27 | 28 | // 双路快速排序的partition 29 | // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p] 30 | func partition2(arr []int,l,r int) int { 31 | rand.Seed(time.Now().Unix()) 32 | randIndex := rand.Int()%(r-l+1)+l 33 | arr[l],arr[randIndex] = arr[randIndex],arr[l] 34 | 35 | v := arr[l] 36 | // arr[l+1...i) <= v; arr(j...r] >= v 37 | i,j := l+1,r 38 | for { 39 | // 注意这里的边界, arr[i] < v, 不能是arr[i] <= v 40 | // 思考一下为什么? 41 | for i <= r && arr[i] < v { 42 | i++ 43 | } 44 | // 注意这里的边界, arr[j] > v, 不能是arr[j] >= v 45 | // 思考一下为什么? 46 | for j >= l + 1 && arr[j] > v { 47 | j-- 48 | } 49 | if i > j { 50 | break 51 | } 52 | arr[j],arr[i] = arr[i],arr[j] 53 | i++ 54 | j-- 55 | } 56 | arr[l],arr[j] = arr[j],arr[l] 57 | return j 58 | } 59 | // 递归的三路快速排序算法 60 | func quickSort3Ways(arr []int,l,r int) { 61 | if l >= r { 62 | return 63 | } 64 | // 对于小规模数组, 我们其实可以使用插入排序进行优化 65 | // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot 66 | rand.Seed(time.Now().Unix()) 67 | randIndex := rand.Int()%(r-l+1)+l 68 | arr[l],arr[randIndex] = arr[randIndex],arr[l] 69 | 70 | v := arr[l] 71 | // arr[l+1...lt] < v 72 | // arr[gt...r] > v 73 | // arr[lt+1...i) == v 74 | lt,gt,i := l,r+1,l+1 75 | for i < gt { 76 | if arr[i] < v { 77 | arr[i],arr[lt + 1] = arr[lt + 1],arr[i] 78 | i++ 79 | lt++ 80 | } else if arr[i]>v { 81 | arr[i],arr[gt-1] = arr[gt-1],arr[i] 82 | gt-- 83 | } else { 84 | i++ 85 | } 86 | } 87 | arr[l],arr[lt] = arr[lt],arr[l] 88 | quickSort3Ways(arr,l,lt-1) 89 | quickSort3Ways(arr,gt,r) 90 | } 91 | 92 | func QuickSort(arr []int,l,r int) { 93 | if l >= r { 94 | return 95 | } 96 | p := partition(arr,l,r) 97 | QuickSort(arr,l,p-1) 98 | QuickSort(arr,p+1,r) 99 | } 100 | 101 | func Quick3Ways(arr []int,n int) { 102 | quickSort3Ways(arr,0,n-1) 103 | } 104 | -------------------------------------------------------------------------------- /Sorts/Select.go: -------------------------------------------------------------------------------- 1 | package Sorts 2 | 3 | func Select(data []int) { 4 | llen := len(data) 5 | for i:=0;i= 1 { 10 | for i := h; i < n ; i++ { 11 | // 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序 12 | e := arr[i] 13 | var j int 14 | for j = i; j>=h && e < arr[j-h]; j-=h { 15 | arr[j] = arr[j-h] 16 | } 17 | arr[j] = e 18 | } 19 | h /= 3 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sorts/Sort_test.go: -------------------------------------------------------------------------------- 1 | package Sorts 2 | 3 | import "testing" 4 | 5 | func BenchmarkSort(t *testing.B) { 6 | var arr []int 7 | for i:=9 ; i>=0;i--{ 8 | arr = append(arr,i) 9 | } 10 | t.Log(arr) 11 | //MergeSort(arr,0,len(arr)-1) 12 | ShellSort(arr,len(arr)) 13 | t.Log(arr) 14 | } 15 | -------------------------------------------------------------------------------- /Trie/Trie.go: -------------------------------------------------------------------------------- 1 | package Trie 2 | // 字典树(前缀树) 3 | 4 | type Node struct { 5 | isWord bool 6 | next map[byte]*Node 7 | } 8 | 9 | func InitNode(isWord bool) *Node { 10 | return &Node{ 11 | isWord:isWord, 12 | next:make(map[byte]*Node), 13 | } 14 | } 15 | func InitNodeWithoutPram() *Node { 16 | return &Node{ 17 | isWord:false, 18 | next:make(map[byte]*Node), 19 | } 20 | } 21 | type Trie struct { 22 | root *Node 23 | size int 24 | } 25 | 26 | func (t Trie) Size() int { 27 | return t.size 28 | } 29 | 30 | func InitTrie() *Trie { 31 | return &Trie{ 32 | root:InitNodeWithoutPram(), 33 | size:0, 34 | } 35 | } 36 | // 向Trie中添加一个新的单词word 37 | func (this *Trie)Push(word string) { 38 | cur := this.root 39 | for _,v := range word { 40 | _,ok:= cur.next[byte(v)] 41 | if !ok { 42 | cur.next[byte(v)] = InitNodeWithoutPram() 43 | } 44 | cur = cur.next[byte(v)] 45 | } 46 | // 判断新来的单词是否之前添加过,没添加过才添加进去 47 | if cur.isWord == false { 48 | cur.isWord = true 49 | this.size++ 50 | } 51 | } 52 | 53 | func (this *Trie) Contains(word string) bool { 54 | cur := this.root 55 | for _,v := range word { 56 | if res,ok := cur.next[byte(v)];ok { 57 | cur = res 58 | } else { 59 | return false 60 | } 61 | } 62 | // 走完了也不一定就一定是true,比如panda和pan我们有panda,pan不一定是我们添加的单词 63 | return cur.isWord 64 | } 65 | 66 | func (this *Trie) SearchPrefix (prefix string) bool { 67 | cur := this.root 68 | for _,v := range prefix { 69 | if res,ok := cur.next[byte(v)];ok { 70 | cur = res 71 | } else { 72 | return false 73 | } 74 | } 75 | return true 76 | } 77 | 78 | func (this *Trie) MatchSearch (word string) bool { 79 | return this.match(this.root,word,0) 80 | } 81 | 82 | func (this *Trie) match (node *Node,word string,index int) bool { 83 | if index == len(word) { 84 | return node.isWord 85 | } 86 | 87 | v := word[index] 88 | if byte(v) != '.' { 89 | if res,ok := node.next[byte(v)];ok { 90 | return this.match(res,word,index+1) 91 | } else { 92 | return false 93 | } 94 | } else { 95 | for k,_ := range node.next { 96 | if this.match(node.next[k],word,index+1) { 97 | return true 98 | } 99 | } 100 | return false 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Trie/Trie_test.go: -------------------------------------------------------------------------------- 1 | package Trie 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "log" 7 | "os" 8 | "strings" 9 | "testing" 10 | "time" 11 | ) 12 | 13 | func TestTrie(t *testing.T) { 14 | trie := InitTrie() 15 | file, err := os.Open("pride-and-prejudice.txt") 16 | if err != nil { 17 | log.Fatal(err) 18 | } 19 | scanner := bufio.NewScanner(file) 20 | // 缺省的分隔函数是bufio.ScanLines,我们这里使用ScanWords。 21 | // 也可以定制一个SplitFunc类型的分隔函数 22 | scanner.Split(bufio.ScanWords) 23 | // scan下一个token. 24 | success := scanner.Scan() 25 | start := time.Now() 26 | for success { 27 | word := scanner.Text() 28 | word = strings.ToLower(word) 29 | for len(word) > 0 && (word[0] < 'a' || word[0] > 'z') { 30 | word = word[1:] 31 | } 32 | for len(word) > 0 && (word[len(word)-1] < 'a' || word[len(word)-1] > 'z') { 33 | word = word[:len(word)-1] 34 | } 35 | trie.Push(word) 36 | success = scanner.Scan() 37 | } 38 | if success == false { 39 | // 出现错误或者EOF是返回Error 40 | err = scanner.Err() 41 | if err == nil { 42 | log.Println("Scan completed and reached EOF") 43 | } else { 44 | log.Fatal(err) 45 | } 46 | } 47 | end := time.Now() 48 | // fmt.Println(trie.SearchPrefix("pri")) 49 | fmt.Println("傲慢与偏见一共",trie.Size(),"个单词") 50 | fmt.Println("统计整本书共用时:",end.Sub(start)) 51 | } 52 | -------------------------------------------------------------------------------- /Union/Find.go: -------------------------------------------------------------------------------- 1 | package Union 2 | 3 | import "errors" 4 | 5 | type UF interface { 6 | Union(p,q int) 7 | IsConnect(p,q int) bool 8 | GetSize() int 9 | } 10 | // 只实现了QuickFind的并查集 11 | type Find struct { 12 | id []int 13 | } 14 | 15 | func InitUnionFind(size int) *Find { 16 | unionFind := &Find{ 17 | id:make([]int,size), 18 | } 19 | for i := range unionFind.id { 20 | unionFind.id[i] = i 21 | } 22 | return unionFind 23 | } 24 | func(this *Find) GetSize () int { 25 | return len(this.id) 26 | } 27 | // 查找元素p对应的元素编号 28 | func(this *Find) Find (p int) (res int, err error) { 29 | if p < 0 || p >= len(this.id) { 30 | err = errors.New("p is out of range") 31 | } else { 32 | res = this.id[p] 33 | } 34 | return 35 | } 36 | // 合并p,q所属的集合 37 | func(this *Find) Union(p,q int) { 38 | var ( 39 | pid int 40 | qid int 41 | err error 42 | ) 43 | pid,err = this.Find(p) 44 | if err != nil { 45 | panic(err) 46 | } 47 | qid,err = this.Find(q) 48 | if err != nil { 49 | panic(err) 50 | } 51 | if pid == qid { 52 | return 53 | } 54 | for i,v := range this.id { 55 | if v == pid { 56 | this.id[i] = qid 57 | } 58 | } 59 | return 60 | } 61 | // 查询元素p,q是否属与一个集合 62 | func(this *Find) IsConnect (p,q int) bool { 63 | pid,_ := this.Find(p) 64 | qid,_ := this.Find(q) 65 | return pid == qid 66 | } 67 | 68 | 69 | type QuickFind struct { 70 | parent []int 71 | } 72 | 73 | func InitUnionQuickFind(size int) *QuickFind { 74 | unionFind := &QuickFind{ 75 | parent:make([]int,size), 76 | } 77 | // 初始化时每个节点都是一颗树 78 | for i := range unionFind.parent { 79 | unionFind.parent[i] = i 80 | } 81 | return unionFind 82 | } 83 | 84 | func(this *QuickFind) GetSize () int { 85 | return len(this.parent) 86 | } 87 | // 查找元素p对应的元素编号,时间复杂度为O(h),h为树的高度 88 | func(this *QuickFind) Find (p int) int { 89 | if p < 0 || p >= len(this.parent) { 90 | panic("p is out of range!") 91 | } else { 92 | for p != this.parent[p] { 93 | p = this.parent[p] 94 | } 95 | } 96 | return p 97 | } 98 | // 合并过程,时间复杂度为O(h),h为树的高度 99 | func(this *QuickFind) Union(p,q int) { 100 | var ( 101 | pid int 102 | qid int 103 | ) 104 | pid = this.Find(p) 105 | qid = this.Find(q) 106 | 107 | if pid == qid { 108 | return 109 | } 110 | this.parent[pid] = qid 111 | return 112 | } 113 | // 查询元素p,q是否属与一个集合 114 | func(this *QuickFind) IsConnect (p,q int) bool { 115 | return this.Find(p) == this.Find(q) 116 | } -------------------------------------------------------------------------------- /Union/Find_test.go: -------------------------------------------------------------------------------- 1 | package Union 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestFind(t *testing.T) { 11 | uni := InitUnionFind(1000000) 12 | size := uni.GetSize() 13 | m := 100000 14 | start := time.Now() 15 | for i:=0;i b.(int) { 16 | return 1 17 | } else if a.(int) < b.(int) { 18 | return -1 19 | } else { 20 | return 0 21 | } 22 | case string: 23 | if a.(string) > b.(string) { 24 | return 1 25 | } else if a.(string) < b.(string) { 26 | return -1 27 | } else { 28 | return 0 29 | } 30 | case float64: 31 | if a.(float64) > b.(float64) { 32 | return 1 33 | } else if a.(float64) < b.(float64) { 34 | return -1 35 | } else { 36 | return 0 37 | } 38 | default: 39 | panic("unsupported type params") 40 | } 41 | } -------------------------------------------------------------------------------- /com_test.go: -------------------------------------------------------------------------------- 1 | package algo 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestCom(t *testing.T){ 9 | res := combinationSum3(3,9) 10 | fmt.Println(res) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /combine.go: -------------------------------------------------------------------------------- 1 | package algo 2 | 3 | func combinationSum3(k int, n int) [][]int { 4 | res := [][]int{} 5 | temp := make([]int, k+1) 6 | used := make([]bool, 10) 7 | 8 | var dfs func(int, int) 9 | dfs = func(idx, remain int) { 10 | if idx == k { 11 | if remain < 10 && !used[remain] { 12 | temp[idx] = remain 13 | t := make([]int, k) 14 | copy(t, temp[1:]) 15 | res = append(res, t) 16 | } 17 | return 18 | } 19 | 20 | for i := temp[idx-1] + 1; i < 10; i++ { 21 | if remain-i < i { 22 | return 23 | } 24 | used[i] = true 25 | temp[idx] = i 26 | dfs(idx+1, remain-i) 27 | used[i] = false 28 | } 29 | } 30 | 31 | dfs(1, n) 32 | 33 | return res 34 | } 35 | -------------------------------------------------------------------------------- /main/622.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type MyCircularQueue struct { 4 | arr []int 5 | front int 6 | rear int 7 | size int 8 | } 9 | 10 | 11 | /** Initialize your data structure here. Set the size of the queue to be k. */ 12 | func Constructor(k int) MyCircularQueue { 13 | return MyCircularQueue{ 14 | make([]int,k), 15 | 0, 16 | 0, 17 | 0, 18 | } 19 | } 20 | 21 | 22 | /** Insert an element into the circular queue. Return true if the operation is successful. */ 23 | func (this *MyCircularQueue) EnQueue(value int) bool { 24 | if this.arr == nil || (this.size == len(this.arr) && (this.rear) % len(this.arr) == this.front){ 25 | return false 26 | } 27 | this.arr[this.rear % len(this.arr)] = value 28 | this.rear = this.rear % len(this.arr)+1 29 | this.size ++ 30 | return true 31 | } 32 | 33 | 34 | /** Delete an element from the circular queue. Return true if the operation is successful. */ 35 | func (this *MyCircularQueue) DeQueue() bool { 36 | if this.arr == nil || this.size == 0 { 37 | return false 38 | }else { 39 | this.front = this.front % len(this.arr) + 1 40 | this.size-- 41 | return true 42 | } 43 | } 44 | 45 | 46 | /** Get the front item from the queue. */ 47 | func (this *MyCircularQueue) Front() int { 48 | if this.IsEmpty() { 49 | return -1 50 | } 51 | return this.arr[this.front] 52 | } 53 | 54 | 55 | /** Get the last item from the queue. */ 56 | func (this *MyCircularQueue) Rear() int { 57 | if this.IsEmpty() { 58 | return -1 59 | } 60 | if this.size > 0 && this.rear == 0 { 61 | return this.arr[len(this.arr)-1] 62 | } 63 | return this.arr[this.rear-1] 64 | } 65 | 66 | 67 | /** Checks whether the circular queue is empty or not. */ 68 | func (this *MyCircularQueue) IsEmpty() bool { 69 | if this.size == 0{ 70 | return true 71 | } 72 | return false 73 | } 74 | 75 | 76 | /** Checks whether the circular queue is full or not. */ 77 | func (this *MyCircularQueue) IsFull() bool { 78 | if this.size == len(this.arr) { 79 | return true 80 | } 81 | return false 82 | } 83 | 84 | 85 | /** 86 | * Your MyCircularQueue object will be instantiated and called as such: 87 | * obj := Constructor(k); 88 | * param_1 := obj.EnQueue(value); 89 | * param_2 := obj.DeQueue(); 90 | * param_3 := obj.Front(); 91 | * param_4 := obj.Rear(); 92 | * param_5 := obj.IsEmpty(); 93 | * param_6 := obj.IsFull(); 94 | */ -------------------------------------------------------------------------------- /main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("hello world") 7 | } -------------------------------------------------------------------------------- /pkg/mod/cache/lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq570850096/awesome-go-datastruct/dd4aa6ed4b37dba3d09f1b5ae098eff7bc95765b/pkg/mod/cache/lock -------------------------------------------------------------------------------- /queue/queue.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Queue struct { 8 | container []int 9 | front int 10 | rear int 11 | size int 12 | } 13 | 14 | 15 | func NewQueue (k int) *Queue { 16 | return &Queue{ 17 | make([]int, k), 18 | 0, 19 | 0, 20 | 0, 21 | } 22 | } 23 | 24 | 25 | func (this *Queue) EnQueue(value int) bool { 26 | if this.container == nil || this.IsFull() { 27 | return false 28 | } 29 | this.container[this.rear%len(this.container)] = value 30 | this.rear = this.rear%len(this.container) + 1 31 | this.size++ 32 | return true 33 | } 34 | 35 | 36 | func (this *Queue) DeQueue() (bool,int) { 37 | if this.container == nil || this.IsEmpty() { 38 | return false,0 39 | } else { 40 | ret := this.container[this.front%len(this.container)] 41 | this.front = this.front%len(this.container) + 1 42 | this.size-- 43 | return true,ret 44 | } 45 | } 46 | 47 | 48 | func (this *Queue) IsEmpty() bool { 49 | if this.size == 0 { 50 | return true 51 | } 52 | return false 53 | } 54 | 55 | func (this *Queue) IsFull() bool { 56 | if this.size == len(this.container) { 57 | return true 58 | } 59 | return false 60 | } 61 | 62 | func main() { 63 | queue := NewQueue(5) 64 | // 循环3次,每次添加5个元素,再出队三个元素 65 | for i:=0; i<3; i++{ 66 | for j:=0;j<5;j++ { 67 | queue.EnQueue(j) 68 | } 69 | for k:=0;k<3;k++ { 70 | fmt.Println(queue.DeQueue()) 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /skiplists/SkipLists.go: -------------------------------------------------------------------------------- 1 | package skiplists 2 | 3 | import "math/rand" 4 | 5 | 6 | const ( 7 | maxLevel int = 16 // Should be enough for 2^16 elements 8 | p float32 = 0.25 9 | ) 10 | // Element is an Element of a skiplist. 11 | type Node struct { 12 | Score float64 13 | Value interface{} 14 | forward []*Node 15 | } 16 | 17 | func newElement(score float64, value interface{}, level int) *Node { 18 | return &Node{ 19 | Score: score, 20 | Value: value, 21 | forward: make([]*Node, level), 22 | } 23 | } 24 | 25 | // SkipList represents a skiplist. 26 | // The zero value from SkipList is an empty skiplist ready to use. 27 | type SkipList struct { 28 | header *Node // header is a dummy element 29 | len int // current skiplist length,header not included 30 | level int // current skiplist level,header not included 31 | } 32 | 33 | // New returns a new empty SkipList. 34 | func New() *SkipList { 35 | return &SkipList{ 36 | header: &Node{forward: make([]*Node, maxLevel)}, 37 | } 38 | } 39 | // 返回长度 40 | func (s *SkipList) Size() int { 41 | return s.len 42 | } 43 | 44 | func randomLevel() int { 45 | level := 1 46 | for rand.Float32() < p && level < maxLevel { 47 | level++ 48 | } 49 | return level 50 | } 51 | 52 | // Front returns first element in the skiplist which maybe nil. 53 | func (sl *SkipList) Front() *Node { 54 | return sl.header.forward[0] 55 | } 56 | 57 | // Next returns first element after e. 58 | func (e *Node) Next() *Node { 59 | if e != nil { 60 | return e.forward[0] 61 | } 62 | return nil 63 | } 64 | 65 | // Search the skiplist to findout element with the given score. 66 | // Returns (*Element, true) if the given score present, otherwise returns (nil, false). 67 | func (sl *SkipList) Search(score float64) (element *Node, ok bool) { 68 | x := sl.header 69 | for i := sl.level - 1; i >= 0; i-- { 70 | for x.forward[i] != nil && x.forward[i].Score < score { 71 | x = x.forward[i] 72 | } 73 | } 74 | x = x.forward[0] 75 | if x != nil && x.Score == score { 76 | return x, true 77 | } 78 | return nil, false 79 | } 80 | 81 | // Insert (score, value) pair to the skiplist and returns pointer of element. 82 | func (sl *SkipList) Insert(score float64, value interface{}) *Node { 83 | update := make([]*Node, maxLevel) 84 | x := sl.header 85 | for i := sl.level - 1; i >= 0; i-- { 86 | for x.forward[i] != nil && x.forward[i].Score < score { 87 | x = x.forward[i] 88 | } 89 | update[i] = x 90 | } 91 | x = x.forward[0] 92 | 93 | // Score already presents, replace with new value then return 94 | if x != nil && x.Score == score { 95 | x.Value = value 96 | return x 97 | } 98 | 99 | level := randomLevel() 100 | if level > sl.level { 101 | level = sl.level + 1 102 | update[sl.level] = sl.header 103 | sl.level = level 104 | } 105 | e := newElement(score, value, level) 106 | for i := 0; i < level; i++ { 107 | e.forward[i] = update[i].forward[i] 108 | update[i].forward[i] = e 109 | } 110 | sl.len++ 111 | return e 112 | } 113 | 114 | // Delete remove and return element with given score, return nil if element not present 115 | func (sl *SkipList) Delete(score float64) *Node { 116 | update := make([]*Node, maxLevel) 117 | x := sl.header 118 | for i := sl.level - 1; i >= 0; i-- { 119 | for x.forward[i] != nil && x.forward[i].Score < score { 120 | x = x.forward[i] 121 | } 122 | update[i] = x 123 | } 124 | x = x.forward[0] 125 | 126 | if x != nil && x.Score == score { 127 | for i := 0; i < sl.level; i++ { 128 | if update[i].forward[i] != x { 129 | return nil 130 | } 131 | update[i].forward[i] = x.forward[i] 132 | } 133 | sl.len-- 134 | } 135 | return x 136 | } -------------------------------------------------------------------------------- /skiplists/SkipLists_test.go: -------------------------------------------------------------------------------- 1 | package skiplists 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestNew(t *testing.T) { 9 | sl := New() 10 | 11 | sl.Insert(float64(100), "foo") 12 | 13 | e, ok := sl.Search(float64(100)) 14 | fmt.Println(ok) 15 | fmt.Println(e.Value) 16 | e, ok = sl.Search(float64(200)) 17 | fmt.Println(ok) 18 | fmt.Println(e) 19 | 20 | sl.Insert(float64(20.5), "bar") 21 | sl.Insert(float64(50), "spam") 22 | sl.Insert(float64(20), 42) 23 | 24 | fmt.Println(sl.Size()) 25 | e = sl.Delete(float64(50)) 26 | fmt.Println(e.Value) 27 | fmt.Println(sl.Size()) 28 | 29 | for e := sl.Front(); e != nil; e = e.Next() { 30 | fmt.Println(e.Value) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /stack/stack.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | type Stack struct { 4 | // 用来装元素的切片 5 | container []byte 6 | // 栈顶标记位 7 | top int 8 | // 容量限制 9 | size int 10 | } 11 | 12 | // 初始化时,要传入容量限制 13 | func NewStack(size int) Stack { 14 | return Stack{ 15 | container: make([]byte,size), 16 | top: 0, 17 | size: size, 18 | } 19 | } 20 | 21 | func (s *Stack) Push (e byte) bool { 22 | if s.IsFull() { 23 | return false 24 | } 25 | s.container[s.top] = e 26 | s.top++ 27 | return true 28 | } 29 | 30 | 31 | func (s *Stack) Pop () (flag bool,ret byte) { 32 | // 如果栈是空的,那么就不能继续 Pop 了 33 | if s.IsEmpty() { 34 | return false,ret 35 | } 36 | ret = s.container[s.top-1] 37 | s.top-- 38 | return true,ret 39 | } 40 | 41 | 42 | func (s *Stack) IsEmpty () bool { 43 | if s.top == 0 { 44 | return true 45 | } 46 | return false 47 | } 48 | 49 | 50 | func (s *Stack) IsFull () bool { 51 | if s.top == s.size { 52 | return true 53 | } 54 | return false 55 | } 56 | 57 | func IsValid(s string) bool { 58 | stack := NewStack(100) 59 | // 遍历括号字符串 60 | for _,v := range s { 61 | if v == '(' { 62 | // 由于golang中的字符串默认是unicode编码,所以我们要做一个强制类型转换 63 | stack.Push(byte(v)) 64 | } 65 | if v == ')' { 66 | if flag,top := stack.Pop(); flag == true &&top == '(' { 67 | continue 68 | } else { 69 | return false 70 | } 71 | } 72 | } 73 | // 字符串遍历完后如果栈也空了,说明括号匹配 74 | if stack.IsEmpty() { 75 | return true 76 | } 77 | // 如果栈不空,说明栈里还有多余的左括号 78 | return false 79 | } 80 | -------------------------------------------------------------------------------- /stack/stack_test.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestNewStack(t *testing.T) { 9 | stack := NewStack(3) 10 | // 先测试栈为空的时候能否Pop 11 | fmt.Println(stack.Pop()) 12 | // 测试Push是否正常 13 | stack.Push(1) 14 | stack.Push(2) 15 | stack.Push(3) 16 | // 如果栈为正常的,这里Pop打印顺序应该是3,2,1 17 | fmt.Println(stack.Pop()) 18 | fmt.Println(stack.Pop()) 19 | 20 | fmt.Println(stack.Pop()) 21 | } 22 | --------------------------------------------------------------------------------