├── README.md ├── anti └── cascadingfailures │ ├── README.md │ └── cascadingfailures.go ├── behavioral ├── chainofresponsibility │ ├── README.md │ ├── chainofresponsibility.go │ └── chainofresponsibility_test.go ├── command │ ├── README.md │ ├── command.go │ └── command_test.go ├── context │ ├── README.md │ ├── context.go │ └── context_test.go ├── interpreter │ ├── README.md │ ├── interpreter.go │ └── interpreter_test.go ├── iterator │ ├── README.md │ ├── book_iterator │ │ ├── book_iterator.go │ │ └── book_iterator_test.go │ ├── iterator.go │ ├── iterator_test.go │ └── person_iterator │ │ ├── iterator.go │ │ └── iterator_test.go ├── mediator │ ├── README.md │ ├── mediator.go │ └── mediator_test.go ├── memento │ ├── README.md │ ├── memento.go │ └── memento_test.go ├── observer │ ├── README.md │ ├── observer.go │ └── observer_test.go ├── registry │ ├── README.md │ ├── registry.go │ └── registry_test.go ├── state │ ├── README.md │ ├── state.go │ └── state_test.go ├── strategy │ ├── README.md │ ├── strategy.go │ └── strategy_test.go ├── templatemethod │ ├── README.md │ ├── example │ │ └── example.go │ ├── templatemethod.go │ └── templatemethod_test.go └── visitor │ ├── README.md │ ├── visitor.go │ └── visitor_test.go ├── concurrency ├── barrier │ ├── README.md │ ├── barrier.go │ └── barrier_test.go ├── batcher │ ├── README.md │ ├── batcher.go │ └── example │ │ ├── README.md │ │ ├── batcher.go │ │ └── batcher_test.go ├── boundedparallelism │ ├── README.md │ ├── bounded_parallelism.go │ └── bounded_parallelism_test.go ├── broadcast │ ├── README.md │ ├── broadcast.go │ └── broadcast_test.go ├── coroutines │ ├── README.md │ └── coroutines.go ├── generator │ ├── README.md │ └── generator.go ├── parallelism │ ├── README.md │ └── parallelism.go ├── producerconsumer │ ├── README.md │ └── producerconsumer.go └── reactor │ ├── README.md │ └── reactor.go ├── creational ├── abstractfactory │ ├── README.md │ ├── abstractfactory.go │ └── abstractfactory_test.go ├── builder │ ├── README.md │ ├── builder.go │ └── builder_test.go ├── factorymethod │ ├── README.md │ ├── factorymethod.go │ └── factorymethod_test.go ├── functionaloption │ ├── README.md │ ├── examples │ │ └── example.go │ ├── functionaloption.go │ └── functionaloption_test.go ├── new │ ├── README.md │ ├── new.go │ └── new_test.go ├── objectpool │ ├── README.md │ ├── objectpool.go │ └── objectpool_test.go ├── prototype │ ├── README.md │ ├── prototype.go │ └── prototype_test.go ├── simplefactory │ ├── README.md │ ├── simplefactory.go │ └── simplefactory_test.go └── singleton │ ├── README.md │ ├── eager.go │ ├── eager_test.go │ ├── lazy.go │ └── lazy_test.go ├── go.mod ├── go.sum ├── images ├── abstract-factorys-method.png ├── breaker-state-machine-flow.png ├── breaker-state-machine.png ├── composite.png ├── pub-sub-pattern-0.png ├── pub-sub-pattern-1.png └── three-code.png ├── messaging ├── fanin │ ├── README.md │ ├── fan_in.go │ └── fan_in_test.go ├── fanout │ ├── README.md │ ├── fan_out.go │ ├── fan_out_complex.go │ ├── fan_out_complex_test.go │ └── fan_out_test.go ├── futurespromises │ ├── README.md │ └── futurespromises.go ├── pubsub │ ├── README.md │ ├── example │ │ ├── README.md │ │ ├── message.go │ │ ├── message_queue.go │ │ ├── message_test.go │ │ ├── message_weather.go │ │ └── message_weather_test.go │ ├── pubsub.go │ └── pubsub_test.go └── pushpull │ ├── README.md │ └── pushpull.go ├── oneintro.md ├── profiling └── timing │ ├── README.md │ └── timing.go ├── stability ├── bulkhead │ ├── README.md │ └── bulkhead.go ├── circuit │ ├── README.md │ ├── circuit.go │ └── example │ │ ├── README.md │ │ ├── breaker │ │ ├── breaker.go │ │ └── breaker_test.go │ │ ├── breaker_options.go │ │ ├── circuit_breaker_adv.go │ │ ├── circuit_breaker_test.go │ │ ├── circuit_counter.go │ │ ├── circuit_func_closure_basic.go │ │ └── gobreaker │ │ ├── README.md │ │ ├── gobreaker.go │ │ ├── gobreaker_example_test.go │ │ └── gobreaker_test.go ├── deadline │ ├── README.md │ ├── deadline.go │ ├── deadline_test.go │ └── examples │ │ ├── example1.go │ │ └── example2.go ├── failfast │ ├── README.md │ └── failfast.go ├── handshaking │ ├── README.md │ └── handshaking.go ├── ratelimiting │ ├── README.md │ ├── rate_limiting.go │ └── rate_limiting_test.go ├── retrier │ ├── README.md │ ├── example │ │ ├── backoffs.go │ │ ├── backoffs_test.go │ │ ├── classifier.go │ │ ├── classifier_test.go │ │ ├── retrier.go │ │ └── retrier_test.go │ └── retrier.go └── steadystate │ ├── README.md │ └── steadystate.go ├── structural ├── adapter │ ├── README.md │ ├── adapter.go │ └── adapter_test.go ├── bridge │ ├── README.md │ ├── bridge.go │ └── bridge_test.go ├── composite │ ├── README.md │ ├── composite.go │ └── composite_test.go ├── decorator │ ├── README.md │ ├── decorator.go │ └── decorator_test.go ├── facade │ ├── README.md │ ├── facade.go │ └── facade_test.go ├── flyweight │ ├── README.md │ ├── flyweight.go │ └── flyweight_test.go └── proxy │ ├── README.md │ ├── proxy.go │ └── proxy_test.go └── synchronization ├── condition ├── README.md ├── condition.go └── condition_test.go ├── lockmutex ├── README.md ├── lockmutex.go └── lockmutex_test.go ├── monitor ├── README.md ├── monitor.go └── monitor_test.go ├── pubsub └── pubsub.go ├── readwritelock ├── README.md ├── readwritelock.go └── readwritelock_test.go ├── rwlock └── rwlock.go └── semaphore ├── README.md ├── semaphore.go └── semaphore_test.go /README.md: -------------------------------------------------------------------------------- 1 | # Go 版设计模式(58 种) 2 | 3 | > 云原生 AI 实战营项目之一,更多精彩项目见:[云原生 AI 实战营](https://konglingfei.com/)。 4 | 5 | 本仓库是 [《Go 设计模式 61 讲》课程](https://konglingfei.com/cloudai/catalog/design-pattern.html) 的源码仓库。里面介绍了 58 种常见的设计模式,及 Go 版代码实现。 6 | 7 | 如果你想全面学习这些设计模式,欢迎加入 [云原生 AI 实战营](https://konglingfei.com)。里面不仅包含了 《Go 设计模式 61 讲》课程,还包含了大量其他高质量的 Go、云原生、AI Infra 课程。 8 | 9 |
10 | 11 | 在 《Go 设计模式 61 讲》课程中一共介绍了 58 种设计模式,这些设计模式列表如下。 12 | 13 | ## 创建型模式(Creational Patterns) 14 | 15 | | 模式名 | 英文名 | 状态 | 16 | | --- | --- | --- | 17 | |[简单工厂模式](./creational/simplefactory)|Simple Factory|✔| 18 | |[工厂方法模式](./creational/factorymethod)|Factory Method|✔| 19 | |[抽象工厂模式](./creational/abstractfactory)|Abstract Factory|✔| 20 | |[建造者模式](./creational/builder)|Builder|✔| 21 | |[原型模式](./creational/prototype)|Prototype|✔| 22 | |[单例模式](./creational/singleton)|Singleton|✔| 23 | |[New 模式](./creational/new)|New|✔| 24 | |[函数选项模式](./creational/functionaloption)|Functional Options|✔| 25 | |[对象池模式](./creational/objectpool)|Object Pool|✔| 26 | 27 | ## 行为型模式(Behavioral Patterns) 28 | 29 | | 模式名 | 英文名 | 状态 | 30 | | --- | --- | --- | 31 | |[中介者模式](./behavioral/mediator)|Mediator|✔| 32 | |[观察者模式](./behavioral/observer)|Observer|✔| 33 | |[命令模式](./behavioral/command)|Command|✔| 34 | |[迭代器模式](./behavioral/iterator)|Iterator|✔| 35 | |[模版方法模式](./behavioral/templatemethod)|Template Method|✔| 36 | |[策略模式](./behavioral/strategy)|Strategy|✔| 37 | |[状态模式](./behavioral/state)|State|✔| 38 | |[备忘录模式](./behavioral/memento)|Memento|✔| 39 | |[解释器模式](./behavioral/interpreter)|Interpreter|✔| 40 | |[责任链模式](./behavioral/chainofresponsibility)|Chain of Responsibility|✔| 41 | |[访问者模式](./behavioral/observer)|Visitor|✔| 42 | |[注册表模式](./behavioral/registry)|Registry|✔| 43 | |[上下文模式](./behavioral/context)|Context|✔| 44 | 45 | ## 结构型模式(Structural Patterns) 46 | 47 | | 模式名 | 英文名 | 状态 | 48 | | --- | --- | --- | 49 | |[外观模式](./structural/facade)|Facade|✔| 50 | |[适配器模式](./structural/adapter)|Adapter|✔| 51 | |[代理模式](./structural/proxy)|Proxy|✔| 52 | |[组合模式](./structural/composite)|Composite|✔| 53 | |[享元模式](./structural/flyweight)|Flyweight|✔| 54 | |[装饰器模式](./structural/decorator)|Decorator|✔| 55 | |[桥接模式](./structural/adapter)|Bridge|✔| 56 | 57 | ## 同步模式(Synchronization Patterns) 58 | 59 | | 模式名 | 英文名 | 状态 | 60 | | --- | --- | --- | 61 | |[条件变量模式](./synchronization/condition)|Condition Variable|✔| 62 | |[互斥锁模式](./synchronization/lockmutex)|Lock/Mutex|✔| 63 | |[监视器模式](./synchronization/monitor)|Monitor|✔| 64 | |[读写锁模式](./synchronization/readwritelock)|Read-Write Lock|✔| 65 | |[信号量模式](./synchronization/semaphore)|Semaphore|✔| 66 | 67 | ## 并发模式(Concurrency Patterns) 68 | 69 | | 模式名 | 英文名 | 状态 | 70 | | --- | --- | --- | 71 | |[屏障模式](./concurrency/barrier)|N-Barrier|✔| 72 | |[有界并行性模式](./concurrency/boundedparallelism)|Bounded Parallelism|✔| 73 | |[广播模式](./concurrency/broadcast)|Broadcast|✔| 74 | |[协程模式](./concurrency/coroutines)|Coroutines|✔| 75 | |[生成器模式](./concurrency/generator)|Generator|✔| 76 | |[反应器模式](./concurrency/reactor)|Reactor|✔| 77 | |[并行模式](./concurrency/parallelism)|Parallelism|✔| 78 | |[生产者消费者模式](./concurrency/producerconsumer)|Producer Consumer|✔| 79 | |[批处理模式](./concurrency/batcher)|Batch Processing|✔| 80 | 81 | ## 消息传递模式(Messaging Patterns) 82 | 83 | | 模式名 | 英文名 | 状态 | 84 | | --- | --- | --- | 85 | |[扇入模式](./messaging/fanin)|Fan-In|✔| 86 | |[扇出模式](./messaging/fanout)|Fan-Out|✔| 87 | |[未来与承诺模式](./messaging/futurespromises)|Futures & Promises|✔| 88 | |[发布订阅模式](./messaging/pubsub)|Publish/Subscribe|✔| 89 | |[推模式与拉模式](./messaging/pushpull)|Push & Pull|✔| 90 | 91 | ## 稳定型模式(Stability Patterns) 92 | 93 | | 模式名 | 英文名 | 状态 | 94 | | --- | --- | --- | 95 | |[隔离模式](./stability/bulkhead)|Bulkheads|✔| 96 | |[断路器模式](./stability/circuit)|Circuit-Breaker|✔| 97 | |[截止期限模式](./stability/deadline)|Deadline|✔| 98 | |[快速失败模式](./stability/failfast)|Fail-Fast|✔| 99 | |[握手模式](./stability/handshaking)|Handshaking|✔| 100 | |[稳态模式](./stability/steadystate)|Steady-State|✔| 101 | |[限流模式](./stability/ratelimiting)|Rate Limiting|✔| 102 | |[重试模式](./stability/retrier)|Retrier|✔| 103 | 104 | ## 分析模式(Profiling Patterns) 105 | 106 | | 模式名 | 英文名 | 状态 | 107 | | --- | --- | --- | 108 | |[计时函数模式](./profiling/timing)|Timing Functions|✔| 109 | 110 | ## 反模式(Anti-Patterns) 111 | 112 | | 模式名 | 英文名 | 状态 | 113 | | --- | --- | --- | 114 | |[串联故障模式](./anti/cascadingfailures)|Cascading Failures|✔| 115 | 116 | ## 参考资料 117 | 118 | | 推荐顺序| 项目名 | 参考星级 | 参考状态 | 119 | | --- | --- | --- | --- | 120 | | 1 | [crazybber/go-pattern-examples](https://github.com/crazybber/go-pattern-examples) | ★★★★★ |✔| 121 | | 2 | [crazybber/awesome-patterns](https://github.com/crazybber/awesome-patterns) | ★★★★★ |✔| 122 | | 3 | [tmrts/go-patterns](https://github.com/tmrts/go-patterns) | ★★★★ |✔| 123 | | 4 | [senghoo/golang-design-pattern](https://github.com/senghoo/golang-design-pattern) | ★★★ |✔| 124 | | 5 | [lee501/go-patterns](https://github.com/lee501/go-patterns) | ★★★ |✔| 125 | | 6 | [mohuishou/go-design-pattern](https://github.com/mohuishou/go-design-pattern) | ★★★ |✔| 126 | 127 | ## Contacts 128 | 129 | 130 | -------------------------------------------------------------------------------- /anti/cascadingfailures/README.md: -------------------------------------------------------------------------------- 1 | ## 串联故障模式 2 | 3 | 串联故障模式(Cascading Failures Pattern)描述了当一个组件或服务的故障引发了系统中其他组件或服务的故障,导致故障的传播与扩大。Cascading Failures 模式在分布式系统和微服务架构中经常出现,对系统的稳定性和可靠性带来挑战。 4 | -------------------------------------------------------------------------------- /anti/cascadingfailures/cascadingfailures.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func componentA() error { 9 | // 模拟组件A的任务 10 | time.Sleep(1 * time.Second) 11 | return fmt.Errorf("Error in component A") 12 | } 13 | 14 | func componentB() error { 15 | // 模拟组件B的任务 16 | time.Sleep(2 * time.Second) 17 | return fmt.Errorf("Error in component B") 18 | } 19 | 20 | func main() { 21 | errA := componentA() 22 | if errA != nil { 23 | fmt.Println("Component A failed:", errA) 24 | 25 | // 处理组件A的故障,避免影响到组件B 26 | errB := componentB() 27 | if errB != nil { 28 | fmt.Println("Component B failed:", errB) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /behavioral/chainofresponsibility/README.md: -------------------------------------------------------------------------------- 1 | ## 责任链模式 2 | 3 | 责任链模式(Chain of Responsibility Pattern)用于将请求从一个处理程序传递到另一个处理程序,直到找到能够处理该请求的处理程序为止。在 Go 语言中,责任链模式通常通过函数闭包和链式调用实现,提高代码的灵活性和可扩展性 4 | -------------------------------------------------------------------------------- /behavioral/chainofresponsibility/chainofresponsibility.go: -------------------------------------------------------------------------------- 1 | package chainofresponsibility 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // IApprover 接口定义了审批人的方法 8 | type IApprover interface { 9 | // SetNext 设置下一个审批人 10 | SetNext(approver IApprover) IApprover 11 | // Approve 批准金额 12 | Approve(amount float64) 13 | } 14 | 15 | // Approver 结构体表示一个审批人 16 | type Approver struct { 17 | limit float64 18 | next IApprover 19 | } 20 | 21 | // NewApprover 创建一个新的审批人 22 | func NewApprover(limit float64) *Approver { 23 | return &Approver{limit: limit} 24 | } 25 | 26 | // SetNext 设置下一个审批人 27 | func (a *Approver) SetNext(approver IApprover) IApprover { 28 | a.next = approver 29 | return a 30 | } 31 | 32 | // Approve 空实现了批准金额的操作,具体逻辑由子类实现 33 | func (a *Approver) Approve(amount float64) {} 34 | 35 | // Manager 结构体表示经理职级的审批人 36 | type Manager struct { 37 | *Approver 38 | } 39 | 40 | // NewManager 创建一个新的经理审批人 41 | func NewManager(limit float64) *Manager { 42 | return &Manager{Approver: NewApprover(limit)} 43 | } 44 | 45 | // Approve 实现经理审批金额的逻辑 46 | func (m *Manager) Approve(amount float64) { 47 | if amount <= m.limit { 48 | fmt.Printf("Manager approved the request for $%.2f\n", amount) 49 | } else if m.next != nil { 50 | m.next.Approve(amount) 51 | } else { 52 | fmt.Println("Request can't be approved at Manager level") 53 | } 54 | } 55 | 56 | // Director 结构体表示总监职级的审批人 57 | type Director struct { 58 | *Approver 59 | } 60 | 61 | // NewDirector 创建一个新的总监审批人 62 | func NewDirector(limit float64) *Director { 63 | return &Director{Approver: NewApprover(limit)} 64 | } 65 | 66 | // Approve 实现总监审批金额的逻辑 67 | func (d *Director) Approve(amount float64) { 68 | if amount <= d.limit { 69 | fmt.Printf("Director approved the request for $%.2f\n", amount) 70 | } else if d.next != nil { 71 | d.next.Approve(amount) 72 | } else { 73 | fmt.Println("Request can't be approved at Director level") 74 | } 75 | } 76 | 77 | // CFO 结构体表示CFO职级的审批人 78 | type CFO struct { 79 | *Approver 80 | } 81 | 82 | // NewCFO 创建一个新的CFO审批人 83 | func NewCFO(limit float64) *CFO { 84 | return &CFO{Approver: NewApprover(limit)} 85 | } 86 | 87 | // Approve 实现CFO审批金额的逻辑 88 | func (c *CFO) Approve(amount float64) { 89 | if amount <= c.limit { 90 | fmt.Printf("CFO approved the request for $%.2f\n", amount) 91 | } else { 92 | fmt.Println("Request can't be approved at CFO level") 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /behavioral/chainofresponsibility/chainofresponsibility_test.go: -------------------------------------------------------------------------------- 1 | package chainofresponsibility 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func ExampleChainOfResponsibility() { 8 | // 创建审批处理程序 9 | manager := NewManager(1000) 10 | director := NewDirector(5000) 11 | cfo := NewCFO(10000) 12 | 13 | // 设置审批链 14 | manager.SetNext(director) 15 | director.SetNext(cfo) 16 | 17 | // 测试审批流程 18 | amounts := []float64{800, 3500, 6000, 12000} 19 | for _, amount := range amounts { 20 | fmt.Printf("Processing approval request for $%.2f\n", amount) 21 | manager.Approve(amount) 22 | fmt.Println() 23 | } 24 | // Output: 25 | // Processing approval request for $800.00 26 | // Manager approved the request for $800.00 27 | // 28 | // Processing approval request for $3500.00 29 | // Director approved the request for $3500.00 30 | // 31 | // Processing approval request for $6000.00 32 | // CFO approved the request for $6000.00 33 | // 34 | // Processing approval request for $12000.00 35 | // Request can't be approved at CFO level 36 | } 37 | -------------------------------------------------------------------------------- /behavioral/command/README.md: -------------------------------------------------------------------------------- 1 | ## 命令模式 2 | 3 | 命令模式(Command Pattern)将请求以命令的形式包裹在对象里面,传递给调用对象,调用对象寻找匹配该命令的对象,将命令给该对象执行。调用对象可以在执行命令前和执行命令后,进行一些通用或者增强操作,例如:排队请求、记录命令运行日志、撤销命令等。命令模式可以将请求的发送者和接收者解耦,使系统更加灵活和可扩展。 4 | -------------------------------------------------------------------------------- /behavioral/command/command.go: -------------------------------------------------------------------------------- 1 | package command 2 | 3 | import "fmt" 4 | 5 | // Command 接口定义了命令的执行方法 6 | type Command interface { 7 | Execute() 8 | } 9 | 10 | // Light 表示灯的接收者 11 | type Light struct { 12 | } 13 | 14 | // TurnOn 打开灯的操作 15 | func (l *Light) TurnOn() { 16 | fmt.Println("Light is on") 17 | } 18 | 19 | // TurnOff 关闭灯的操作 20 | func (l *Light) TurnOff() { 21 | fmt.Println("Light is off") 22 | } 23 | 24 | // TurnOnCommand 表示开灯命令 25 | type TurnOnCommand struct { 26 | light *Light 27 | } 28 | 29 | // Execute 执行开灯命令 30 | func (c *TurnOnCommand) Execute() { 31 | c.light.TurnOn() 32 | } 33 | 34 | // TurnOffCommand 表示关灯命令 35 | type TurnOffCommand struct { 36 | light *Light 37 | } 38 | 39 | // Execute 执行关灯命令 40 | func (c *TurnOffCommand) Execute() { 41 | c.light.TurnOff() 42 | } 43 | 44 | // Invoker 表示调用者 45 | type Invoker struct { 46 | command Command 47 | } 48 | 49 | // ExecuteCommand 调用执行命令 50 | func (i *Invoker) ExecuteCommand() { 51 | i.command.Execute() 52 | } 53 | -------------------------------------------------------------------------------- /behavioral/command/command_test.go: -------------------------------------------------------------------------------- 1 | package command 2 | 3 | func ExampleCommand() { 4 | // 创建灯对象 5 | light := &Light{} 6 | 7 | // 创建开灯和关灯命令对象 8 | turnOnCommand := &TurnOnCommand{light: light} 9 | turnOffCommand := &TurnOffCommand{light: light} 10 | 11 | // 创建调用者对象并执行命令 12 | invoker := Invoker{command: turnOnCommand} 13 | invoker.ExecuteCommand() 14 | 15 | invoker.command = turnOffCommand 16 | invoker.ExecuteCommand() 17 | // Output: 18 | // Light is on 19 | // Light is off 20 | } 21 | -------------------------------------------------------------------------------- /behavioral/context/README.md: -------------------------------------------------------------------------------- 1 | ## 上下文模式 2 | 3 | 上下文模式(Context)用于在应用程序中传递和管理请求间的各种数据和信息。通过上下文对象,可以在不同组件之间共享数据、状态和配置信息,以实现解耦和提高灵活性。 4 | -------------------------------------------------------------------------------- /behavioral/context/context.go: -------------------------------------------------------------------------------- 1 | package context 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | type RequestInfo struct { 10 | Username string 11 | IPAddress string 12 | } 13 | 14 | func processRequest(ctx context.Context, req RequestInfo) { 15 | // 从上下文中获取请求信息 16 | username := req.Username 17 | // 模拟处理请求的逻辑 18 | fmt.Printf("Processing request from user %s at IP %s\n", username, req.IPAddress) 19 | // 等待一段时间模拟处理请求 20 | time.Sleep(2 * time.Second) 21 | } 22 | -------------------------------------------------------------------------------- /behavioral/context/context_test.go: -------------------------------------------------------------------------------- 1 | package context 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | func ExampleContext() { 8 | // 创建上下文对象,并设置请求信息 9 | ctx := context.Background() 10 | req := RequestInfo{ 11 | Username: "Alice", 12 | IPAddress: "192.168.1.1", 13 | } 14 | 15 | // 在上下文中传递请求信息 16 | ctx = context.WithValue(ctx, "request", req) 17 | 18 | // 处理请求 19 | processRequest(ctx, req) 20 | // Output: 21 | // Processing request from user Alice at IP 192.168.1.1 22 | } 23 | -------------------------------------------------------------------------------- /behavioral/interpreter/README.md: -------------------------------------------------------------------------------- 1 | ## 解释器模式 2 | 3 | 解释器模式(Interpreter Pattern)用于定义一种语言的文法,并提供一个解释器来解释该语言中的表达式。解释器模式将文法表示成一个语法树,并通过解释器逐个解释语法树节点,从而实现根据特定规则解释和执行程序。 4 | -------------------------------------------------------------------------------- /behavioral/interpreter/interpreter.go: -------------------------------------------------------------------------------- 1 | package interpreter 2 | 3 | // Expression 是解释器接口,定义了解释器的方法 4 | type Expression interface { 5 | Interpret() int 6 | } 7 | 8 | // Number 表示一个数字表达式 9 | type Number struct { 10 | value int 11 | } 12 | 13 | // Interpret 实现了Expression接口的Interpret方法,返回数字值 14 | func (n *Number) Interpret() int { 15 | return n.value 16 | } 17 | 18 | // Add 表示加法表达式 19 | type Add struct { 20 | left Expression 21 | right Expression 22 | } 23 | 24 | // Interpret 实现了Expression接口的Interpret方法,对左右表达式进行相加操作 25 | func (a *Add) Interpret() int { 26 | return a.left.Interpret() + a.right.Interpret() 27 | } 28 | 29 | // Subtract 表示减法表达式 30 | type Subtract struct { 31 | left Expression 32 | right Expression 33 | } 34 | 35 | // Interpret 实现了Expression接口的Interpret方法,对左右表达式进行相减操作 36 | func (s *Subtract) Interpret() int { 37 | return s.left.Interpret() - s.right.Interpret() 38 | } 39 | -------------------------------------------------------------------------------- /behavioral/interpreter/interpreter_test.go: -------------------------------------------------------------------------------- 1 | package interpreter 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func ExampleInterpreter() { 8 | // 构建表达式:4 + 2 - 3 9 | expression := Subtract{ 10 | left: &Add{ 11 | left: &Number{value: 4}, 12 | right: &Number{value: 2}, 13 | }, 14 | right: &Number{value: 3}, 15 | } 16 | 17 | // 解释表达式并计算结果 18 | result := expression.Interpret() 19 | fmt.Println("Result:", result) 20 | // Output: 21 | // Result: 3 22 | } 23 | -------------------------------------------------------------------------------- /behavioral/iterator/README.md: -------------------------------------------------------------------------------- 1 | ## 迭代器模式 2 | 3 | 迭代器模式(Iterator Pattern)用于提供一种方法来顺序访问一个聚合对象中的各个元素,而无需暴露其内部实现方式。迭代器模式将迭代操作从聚合对象中分离出来,让客户端可以独立地遍历聚合对象中的元素,同时保持代码的简洁性和可维护性。 4 | -------------------------------------------------------------------------------- /behavioral/iterator/book_iterator/book_iterator.go: -------------------------------------------------------------------------------- 1 | // Package iterator is an example of the Iterator Pattern. 2 | package iterator 3 | 4 | // Iterator provides a iterator interface. 5 | type Iterator interface { 6 | Index() int 7 | Value() interface{} 8 | Has() bool 9 | Next() 10 | Prev() 11 | Reset() 12 | End() 13 | } 14 | 15 | // Aggregate provides a collection interface. 16 | type Aggregate interface { 17 | Iterator() Iterator 18 | } 19 | 20 | // BookIterator implements the Iterator interface. 21 | type BookIterator struct { 22 | shelf *BookShelf 23 | index int 24 | internal int 25 | } 26 | 27 | // Index returns current index 28 | func (i *BookIterator) Index() int { 29 | return i.index 30 | } 31 | 32 | // Value returns current value 33 | func (i *BookIterator) Value() interface{} { 34 | return i.shelf.Books[i.index] 35 | } 36 | 37 | // Has implementation. 38 | func (i *BookIterator) Has() bool { 39 | if i.internal < 0 || i.internal >= len(i.shelf.Books) { 40 | return false 41 | } 42 | return true 43 | } 44 | 45 | // Next goes to the next item. 46 | func (i *BookIterator) Next() { 47 | i.internal++ 48 | if i.Has() { 49 | i.index++ 50 | } 51 | } 52 | 53 | // Prev goes to the previous item. 54 | func (i *BookIterator) Prev() { 55 | i.internal-- 56 | if i.Has() { 57 | i.index-- 58 | } 59 | } 60 | 61 | // Reset resets iterator. 62 | func (i *BookIterator) Reset() { 63 | i.index = 0 64 | i.internal = 0 65 | } 66 | 67 | // End goes to the last item. 68 | func (i *BookIterator) End() { 69 | i.index = len(i.shelf.Books) - 1 70 | i.internal = i.index 71 | } 72 | 73 | // BookShelf implements the Aggregate interface. 74 | type BookShelf struct { 75 | Books []*Book 76 | } 77 | 78 | // Iterator creates and returns the iterator over the collection. 79 | func (b *BookShelf) Iterator() Iterator { 80 | return &BookIterator{shelf: b} 81 | } 82 | 83 | // Add adds an item to the collection. 84 | func (b *BookShelf) Add(book *Book) { 85 | b.Books = append(b.Books, book) 86 | } 87 | 88 | // Book implements a item of the collection. 89 | type Book struct { 90 | Name string 91 | } 92 | -------------------------------------------------------------------------------- /behavioral/iterator/book_iterator/book_iterator_test.go: -------------------------------------------------------------------------------- 1 | // Package iterator is an example of the Iterator Pattern. 2 | package iterator 3 | 4 | import "testing" 5 | 6 | func TestIterator(t *testing.T) { 7 | 8 | shelf := new(BookShelf) 9 | 10 | books := []string{"A", "B", "C", "D", "E", "F"} 11 | 12 | for _, book := range books { 13 | shelf.Add(&Book{Name: book}) 14 | } 15 | 16 | for iterator := shelf.Iterator(); iterator.Has(); iterator.Next() { 17 | index, value := iterator.Index(), iterator.Value().(*Book) 18 | if value.Name != books[index] { 19 | t.Errorf("Expect Book.Name to %s, but %s", books[index], value.Name) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /behavioral/iterator/iterator.go: -------------------------------------------------------------------------------- 1 | package iterator 2 | 3 | // Iterator 定义迭代器接口 4 | type Iterator interface { 5 | HasNext() bool // 是否有下一个元素 6 | Next() string // 获取下一个元素 7 | } 8 | 9 | // ConcreteIterator 具体迭代器实现 10 | type ConcreteIterator struct { 11 | index int // 迭代器当前位置 12 | data []string // 数据集合 13 | } 14 | 15 | // NewConcreteIterator 创建新的具体迭代器实例 16 | func NewConcreteIterator(data []string) *ConcreteIterator { 17 | return &ConcreteIterator{index: 0, data: data} 18 | } 19 | 20 | // HasNext 实现迭代器接口,判断是否有下一个元素 21 | func (it *ConcreteIterator) HasNext() bool { 22 | return it.index < len(it.data) 23 | } 24 | 25 | // Next 实现迭代器接口,获取下一个元素 26 | func (it *ConcreteIterator) Next() string { 27 | if !it.HasNext() { 28 | return "" 29 | } 30 | value := it.data[it.index] 31 | it.index++ 32 | return value 33 | } 34 | 35 | // Aggregate 聚合对象接口 36 | type Aggregate interface { 37 | CreateIterator() Iterator // 创建迭代器 38 | } 39 | 40 | // ConcreteAggregate 具体聚合对象实现 41 | type ConcreteAggregate struct { 42 | data []string // 数据集合 43 | } 44 | 45 | // NewConcreteAggregate 创建新的具体聚合对象实例 46 | func NewConcreteAggregate(data []string) *ConcreteAggregate { 47 | return &ConcreteAggregate{data: data} 48 | } 49 | 50 | // CreateIterator 实现聚合对象接口,创建迭代器 51 | func (a *ConcreteAggregate) CreateIterator() Iterator { 52 | return NewConcreteIterator(a.data) 53 | } 54 | -------------------------------------------------------------------------------- /behavioral/iterator/iterator_test.go: -------------------------------------------------------------------------------- 1 | package iterator 2 | 3 | import "fmt" 4 | 5 | func ExampleIterator() { 6 | // 创建具体聚合对象 7 | aggregate := NewConcreteAggregate([]string{"apple", "banana", "cherry", "date"}) 8 | 9 | // 获取迭代器 10 | iterator := aggregate.CreateIterator() 11 | 12 | // 遍历元素并输出 13 | for iterator.HasNext() { 14 | fmt.Println(iterator.Next()) 15 | } 16 | // Output: 17 | // apple 18 | // banana 19 | // cherry 20 | // date 21 | } 22 | -------------------------------------------------------------------------------- /behavioral/iterator/person_iterator/iterator.go: -------------------------------------------------------------------------------- 1 | package iterator 2 | 3 | import "fmt" 4 | 5 | /* 6 | 设计思想: 7 | 1. Iterator结构体 8 | 实现Next() HasNext()方法 9 | 2. Container容器 10 | 容器实现添加 移除Visitor 和 11 | */ 12 | //创建迭代器 13 | type Iterator struct { 14 | index int 15 | Container 16 | } 17 | 18 | func (i *Iterator) Next() Visitor { 19 | fmt.Println(i.index) 20 | visitor := i.list[i.index] 21 | i.index += 1 22 | return visitor 23 | } 24 | 25 | func (i *Iterator) HasNext() bool { 26 | if i.index >= len(i.list) { 27 | return false 28 | } 29 | return true 30 | } 31 | 32 | // 创建容器 33 | type Container struct { 34 | list []Visitor 35 | } 36 | 37 | func (c *Container) Add(visitor Visitor) { 38 | c.list = append(c.list, visitor) 39 | } 40 | 41 | func (c *Container) Remove(index int) { 42 | if index < 0 || index > len(c.list) { 43 | return 44 | } 45 | c.list = append(c.list[:index], c.list[index+1:]...) 46 | } 47 | 48 | // 创建Visitor接口 49 | type Visitor interface { 50 | Visit() 51 | } 52 | 53 | // 创建具体的visitor对象 54 | type Teacher struct{} 55 | 56 | type Analysis struct{} 57 | 58 | func (t *Teacher) Visit() { 59 | fmt.Println("this is teacher visitor") 60 | } 61 | 62 | func (a *Analysis) Visit() { 63 | fmt.Println("this is analysis visitor") 64 | } 65 | 66 | // 工厂方法创建迭代器 67 | func NewIterator() *Iterator { 68 | return &Iterator{ 69 | index: 0, 70 | Container: Container{}, 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /behavioral/iterator/person_iterator/iterator_test.go: -------------------------------------------------------------------------------- 1 | package iterator 2 | 3 | import "testing" 4 | 5 | func TestIterator_Next(t *testing.T) { 6 | teacher := new(Teacher) 7 | analysis := new(Analysis) 8 | //迭代器 9 | iterator := NewIterator() 10 | iterator.Add(teacher) 11 | iterator.Add(analysis) 12 | if len(iterator.list) != 2 { 13 | t.Error("期望的count is 2") 14 | } 15 | for iterator.HasNext() { 16 | iterator.Next().Visit() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /behavioral/mediator/README.md: -------------------------------------------------------------------------------- 1 | ## 中介者模式 2 | 3 | 中介者模式(Mediator Pattern)旨在减少对象之间的直接依赖关系,以促进对象之间的松耦合。在中介者模式中,所有对象不再直接彼此通信,而是通过一个中介者对象进行通信。这种模式有助于降低系统的复杂性,提高可维护性,并支持系统的扩展性。 4 | -------------------------------------------------------------------------------- /behavioral/mediator/mediator.go: -------------------------------------------------------------------------------- 1 | package mediator 2 | 3 | import "fmt" 4 | 5 | // Mediator 是中介者接口 6 | type Mediator interface { 7 | SendMessage(sender Colleague, message string) // 发送消息给参与者 8 | } 9 | 10 | // ConcreteMediator 是具体中介者 11 | type ConcreteMediator struct { 12 | colleagues []Colleague 13 | } 14 | 15 | // NewConcreteMediator 创建一个新的具体中介者实例 16 | func NewConcreteMediator() *ConcreteMediator { 17 | return &ConcreteMediator{colleagues: make([]Colleague, 0)} 18 | } 19 | 20 | // AddColleague 添加参与者到中介者 21 | func (m *ConcreteMediator) AddColleague(colleague Colleague) { 22 | m.colleagues = append(m.colleagues, colleague) 23 | } 24 | 25 | // SendMessage 实现中介者接口,发送消息给其他参与者 26 | func (m *ConcreteMediator) SendMessage(sender Colleague, message string) { 27 | for _, c := range m.colleagues { 28 | if c != sender { // 不发送给自身 29 | c.ReceiveMessage(message) 30 | } 31 | } 32 | } 33 | 34 | // Colleague 是参与者接口 35 | type Colleague interface { 36 | SendMessage(message string) // 发送消息给其他参与者 37 | ReceiveMessage(message string) // 接收消息 38 | SetMediator(mediator Mediator) // 设置中介者 39 | } 40 | 41 | // User 是用户参与者 42 | type User struct { 43 | name string 44 | mediator Mediator 45 | } 46 | 47 | // NewUser 创建一个新的用户参与者 48 | func NewUser(name string) *User { 49 | return &User{name: name} 50 | } 51 | 52 | // SendMessage 实现参与者接口,通过中介者发送消�� 53 | func (u *User) SendMessage(message string) { 54 | u.mediator.SendMessage(u, message) 55 | } 56 | 57 | // ReceiveMessage 实现参与者接口,接收消息 58 | func (u *User) ReceiveMessage(message string) { 59 | fmt.Printf("[%s] Received message: %s\n", u.name, message) 60 | } 61 | 62 | // SetMediator 实现参与者接口,设置中介者 63 | func (u *User) SetMediator(mediator Mediator) { 64 | u.mediator = mediator 65 | } 66 | -------------------------------------------------------------------------------- /behavioral/mediator/mediator_test.go: -------------------------------------------------------------------------------- 1 | package mediator 2 | 3 | func ExampleMediator() { 4 | // 创建一个新的具体中介者实例 5 | mediator := NewConcreteMediator() 6 | 7 | // 创建三个用户参与者 8 | user1 := NewUser("Alice") 9 | user2 := NewUser("Bob") 10 | user3 := NewUser("Charlie") 11 | 12 | // 将用户参与者添加到中介者 13 | mediator.AddColleague(user1) 14 | mediator.AddColleague(user2) 15 | mediator.AddColleague(user3) 16 | 17 | // 为每个用户参与者设置中介者 18 | user1.SetMediator(mediator) 19 | user2.SetMediator(mediator) 20 | user3.SetMediator(mediator) 21 | 22 | // 发送消息给所有用户参与者 23 | user1.SendMessage("Hello, everyone!") 24 | user2.SendMessage("Hi, there!") 25 | user3.SendMessage("Hey, guys!") 26 | // Output: 27 | // [Bob] Received message: Hello, everyone! 28 | // [Charlie] Received message: Hello, everyone! 29 | // [Alice] Received message: Hi, there! 30 | // [Charlie] Received message: Hi, there! 31 | // [Alice] Received message: Hey, guys! 32 | // [Bob] Received message: Hey, guys! 33 | } 34 | -------------------------------------------------------------------------------- /behavioral/memento/README.md: -------------------------------------------------------------------------------- 1 | ## 备忘录模式 2 | 3 | 备忘录模式(Memento Pattern)允许将对象在不暴露其内部状态的情况下捕获并存储这些状态,并在后续将对象恢复到先前的状态。备忘录模式通常由三个核心角色组成:发起人(Originator)、备忘录(Memento)、管理者(Caretaker)。在实际应用中,备忘录模式常用于实现撤销操作、历史记录功能等。 4 | -------------------------------------------------------------------------------- /behavioral/memento/memento.go: -------------------------------------------------------------------------------- 1 | package memento 2 | 3 | import "fmt" 4 | 5 | // History 定义历史记录结构体 6 | type History struct { 7 | body string // 历史记录内容 8 | } 9 | 10 | // GetBody 获取历史记录内容 11 | func (h *History) GetBody() string { 12 | return h.body 13 | } 14 | 15 | // SetBody 设置历史记录内容 16 | func (h *History) SetBody(body string) { 17 | h.body = body 18 | } 19 | 20 | // NewHistory 创建新的历史记录对象实例 21 | func NewHistory(body string) *History { 22 | return &History{body: body} 23 | } 24 | 25 | // Doc 定义文档结构体 26 | type Doc struct { 27 | title string // 文档标题 28 | body string // 文档内容 29 | } 30 | 31 | // Title 获取文档标题 32 | func (d *Doc) Title() string { 33 | return d.title 34 | } 35 | 36 | // SetTitle 设置文档标题 37 | func (d *Doc) SetTitle(title string) { 38 | d.title = title 39 | } 40 | 41 | // Body 获取文档内容 42 | func (d *Doc) Body() string { 43 | return d.body 44 | } 45 | 46 | // SetBody 设置文档内容 47 | func (d *Doc) SetBody(body string) { 48 | d.body = body 49 | } 50 | 51 | // NewDoc 创建新的文档对象实例 52 | func NewDoc(title string) *Doc { 53 | return &Doc{title: title} 54 | } 55 | 56 | // CreateHistory 创建文档的历史记录 57 | func (d *Doc) CreateHistory() *History { 58 | return &History{body: d.body} 59 | } 60 | 61 | // RestoreHistory 恢复文档的历史记录 62 | func (d *Doc) RestoreHistory(history *History) { 63 | d.body = history.GetBody() 64 | } 65 | 66 | // Editor 定义编辑器结构体 67 | type Editor struct { 68 | doc *Doc // 当前编辑的文档 69 | histories []*History // 编辑历史记录数组 70 | position int // 当前历史记录位置 71 | } 72 | 73 | // NewEditor 创建新的编辑器实例 74 | func NewEditor(doc *Doc) *Editor { 75 | fmt.Println("打开文档" + doc.Title()) 76 | e := &Editor{doc: doc} 77 | e.histories = make([]*History, 0) 78 | return e 79 | } 80 | 81 | // Append 在文档末尾添加文本内容 82 | func (e *Editor) Append(text string) { 83 | e.backup() 84 | 85 | e.doc.SetBody(e.doc.Body() + text + "\n") 86 | 87 | fmt.Println("===> 插入操作,文档内容如下:") 88 | e.Show() 89 | } 90 | 91 | // Save 保存文档内容 92 | func (e *Editor) Save() { 93 | fmt.Println("===> 存盘操作") 94 | } 95 | 96 | // Delete 删除文档内容 97 | func (e *Editor) Delete() { 98 | e.backup() 99 | 100 | fmt.Println("===> 删除操作,文档内容如下:") 101 | e.doc.SetBody("") 102 | } 103 | 104 | // Show 显示文档内容 105 | func (e *Editor) Show() { 106 | fmt.Println(e.doc.Body()) 107 | } 108 | 109 | // backup 备份当前文档状态 110 | func (e *Editor) backup() { 111 | e.histories = append(e.histories, e.doc.CreateHistory()) 112 | e.position++ 113 | } 114 | 115 | // Undo 撤销操作,恢复历史状态 116 | func (e *Editor) Undo() { 117 | // 到头了不可以再撤回 118 | if e.position == 0 { 119 | return 120 | } 121 | e.position-- 122 | history := e.histories[e.position] 123 | e.doc.RestoreHistory(history) 124 | 125 | fmt.Println("===> 撤销操作,文档内容如下:") 126 | e.Show() 127 | } 128 | -------------------------------------------------------------------------------- /behavioral/memento/memento_test.go: -------------------------------------------------------------------------------- 1 | package memento 2 | 3 | func ExampleMemento() { 4 | editor := NewEditor(NewDoc("《孔令飞沉思录》")) 5 | editor.Append("标题:自我晋升篇") 6 | editor.Append("标题:自我觉醒篇") 7 | editor.Append("标题:自我反思篇") 8 | 9 | editor.Delete() 10 | editor.Show() 11 | 12 | editor.Undo() 13 | editor.Undo() 14 | // Output: 15 | // 打开文档《孔令飞沉思录》 16 | // ===> 插入操作,文档内容如下: 17 | // 标题:自我晋升篇 18 | // 19 | // ===> 插入操作,文档内容如下: 20 | // 标题:自我晋升篇 21 | // 标题:自我觉醒篇 22 | // 23 | // ===> 插入操作,文档内容如下: 24 | // 标题:自我晋升篇 25 | // 标题:自我觉醒篇 26 | // 标题:自我反思篇 27 | // 28 | // ===> 删除操作,文档内容如下: 29 | // 30 | // ===> 撤销操作,文档内容如下: 31 | // 标题:自我晋升篇 32 | // 标题:自我觉醒篇 33 | // 标题:自我反思篇 34 | // 35 | // ===> 撤销操作,文档内容如下: 36 | // 标题:自我晋升篇 37 | // 标题:自我觉醒篇 38 | } 39 | -------------------------------------------------------------------------------- /behavioral/observer/README.md: -------------------------------------------------------------------------------- 1 | ## 观察者模式 2 | 3 | 观察者模式Obserser Pattern)定义了一种一对多的依赖关系,让多个观察者对象同时监听并收到被观察对象的状态变化通知。在观察者模式中,主题(Subject)维护一个观察者(Observer)列表,并在状态发生变化时通知观察者。 4 | -------------------------------------------------------------------------------- /behavioral/observer/observer.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import "fmt" 4 | 5 | // Subject 主题接口定义了主题对象应该实现的方法 6 | type Subject interface { 7 | Register(observer Observer) // Register 注册一个观察者 8 | Deregister(observer Observer) // Deregister 注销一个观察者 9 | Notify(message string) // Notify 发送通知给所有观察者 10 | } 11 | 12 | // Observer 观察者接口定义了观察者对象应该实现的方法 13 | type Observer interface { 14 | Update(message string) // Update 接收更新通知 15 | } 16 | 17 | // ConcreteSubject 具体主题实现了 Subject 接口,维护了观察者列表 18 | type ConcreteSubject struct { 19 | observers []Observer // 观察者列表 20 | } 21 | 22 | // NewConcreteSubject 创建一个新的 ConcreteSubject 实例 23 | func NewConcreteSubject() *ConcreteSubject { 24 | return &ConcreteSubject{} 25 | } 26 | 27 | // Register 实现了 Subject 接口的注册方法 28 | func (s *ConcreteSubject) Register(observer Observer) { 29 | s.observers = append(s.observers, observer) 30 | } 31 | 32 | // Deregister 实现了 Subject 接口的注销方法 33 | func (s *ConcreteSubject) Deregister(observer Observer) { 34 | for i, obs := range s.observers { 35 | if obs == observer { 36 | s.observers = append(s.observers[:i], s.observers[i+1:]...) 37 | break 38 | } 39 | } 40 | } 41 | 42 | // Notify 实现了 Subject 接口的通知方法,并通知所有观察者 43 | func (s *ConcreteSubject) Notify(message string) { 44 | fmt.Println("系统:韭菜们,股票暴涨,大家快买!") 45 | for _, observer := range s.observers { 46 | observer.Update(message) 47 | } 48 | } 49 | 50 | // ConcreteObserver 具体观察者实现了 Observer 接口 51 | type ConcreteObserver struct { 52 | name string // 观察者名称 53 | } 54 | 55 | // NewConcreteObserver 创建一个新的 ConcreteObserver 实例 56 | func NewConcreteObserver(name string) *ConcreteObserver { 57 | return &ConcreteObserver{name: name} 58 | } 59 | 60 | // Update 实现了 Observer 接口的更新方法 61 | func (o *ConcreteObserver) Update(message string) { 62 | fmt.Printf("%s: 收到信息<%s>并激进购入股票!\n", o.name, message) 63 | } 64 | -------------------------------------------------------------------------------- /behavioral/observer/observer_test.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | func ExampleObserver() { 4 | // 创建一个主题对象 5 | subject := NewConcreteSubject() 6 | 7 | // 创建两个观察者对象并注册到主题中 8 | observer1 := NewConcreteObserver("韭菜一号") 9 | observer2 := NewConcreteObserver("韭菜二号") 10 | subject.Register(observer1) 11 | subject.Register(observer2) 12 | 13 | // 发送通知给所有观察者 14 | subject.Notify("腾讯股票即将暴涨") 15 | 16 | // 注销观察者 observer2 17 | subject.Deregister(observer2) 18 | 19 | // 再次发送通知给观察者 20 | subject.Notify("字节股票即将暴涨") 21 | // Output: 22 | // 系统:韭菜们,股票暴涨,大家快买! 23 | // 韭菜一号: 收到信息<腾讯股票即将暴涨>并激进购入股票! 24 | // 韭菜二号: 收到信息<腾讯股票即将暴涨>并激进购入股票! 25 | // 系统:韭菜们,股票暴涨,大家快买! 26 | // 韭菜一号: 收到信息<字节股票即将暴涨>并激进购入股票! 27 | } 28 | -------------------------------------------------------------------------------- /behavioral/registry/README.md: -------------------------------------------------------------------------------- 1 | ## 注册表模式 2 | 3 | 注册表模式(Registry Pattern)用于管理应用程序中的全局对象、服务或模块,允许将这些对象注册到一个集中的注册表中,并在需要时进行检索和使用。注册表模式提供了一种灵活的方式来管理和访问全局对象,同时可以实现对象的延迟加载和解耦应用程序组件。 4 | -------------------------------------------------------------------------------- /behavioral/registry/registry.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | // Registry 定义注册表结构 4 | type Registry struct { 5 | registry map[string]interface{} 6 | } 7 | 8 | // Register 方法用于向注册表中注册对象 9 | func (r *Registry) Register(key string, value interface{}) { 10 | r.registry[key] = value 11 | } 12 | 13 | // Get 方法用于从注册表中检索对象 14 | func (r *Registry) Get(key string) interface{} { 15 | return r.registry[key] 16 | } 17 | -------------------------------------------------------------------------------- /behavioral/registry/registry_test.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func ExampleRegistry() { 8 | // 创建注册表实例 9 | reg := Registry{ 10 | registry: make(map[string]interface{}), 11 | } 12 | 13 | // 注册对象到注册表中 14 | reg.Register("logger", "LoggerInstance") 15 | reg.Register("database", "DatabaseInstance") 16 | 17 | // 从注册表中获取对象并使用 18 | logger := reg.Get("logger").(string) 19 | database := reg.Get("database").(string) 20 | 21 | fmt.Println("Logger:", logger) 22 | fmt.Println("Database:", database) 23 | // Output: 24 | // Logger: LoggerInstance 25 | // Database: DatabaseInstance 26 | } 27 | -------------------------------------------------------------------------------- /behavioral/state/README.md: -------------------------------------------------------------------------------- 1 | ## 状态模式 2 | 3 | 状态模式(State Pattern)主要解决的是复杂的状态之间的转换问题。其核心目的就是设计一个状态机,用状态的改变/流转驱动行为变化,同时将状态的实现放在外部,以方便扩展状态。 4 | -------------------------------------------------------------------------------- /behavioral/state/state.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | import "fmt" 4 | 5 | // 状态接口:定义通用的状态规范标准. 6 | type State interface { 7 | ToGreen(light *TrafficLight) 8 | ToYellow(light *TrafficLight) 9 | ToRed(light *TrafficLight) 10 | } 11 | 12 | // 定义一个交通信号灯. 13 | type TrafficLight struct { 14 | state State 15 | } 16 | 17 | // 创建一个交通信号灯,并初始化状态为红灯. 18 | func NewTrafficLight() *TrafficLight { 19 | return &TrafficLight{ 20 | state: NewRed(), 21 | } 22 | } 23 | 24 | // 设置状态 25 | func (t *TrafficLight) SetState(state State) { 26 | t.state = state 27 | } 28 | 29 | // 转换为绿灯 30 | func (t *TrafficLight) ToGreen() { 31 | t.state.ToGreen(t) 32 | } 33 | 34 | // 转换为黄灯 35 | func (t *TrafficLight) ToYellow() { 36 | t.state.ToYellow(t) 37 | } 38 | 39 | // 转换为红灯 40 | func (t *TrafficLight) ToRed() { 41 | t.state.ToRed(t) 42 | } 43 | 44 | // 定义一个红灯 45 | type Red struct{} 46 | 47 | // 创建一个红灯实例 48 | func NewRed() *Red { 49 | return &Red{} 50 | } 51 | 52 | // 转换为绿灯 53 | func (r *Red) ToGreen(light *TrafficLight) { 54 | fmt.Println("错误,红灯不可以切换为绿灯!") 55 | } 56 | 57 | // 转换为黄灯 58 | func (r *Red) ToYellow(light *TrafficLight) { 59 | fmt.Println("黄灯亮起 5 秒!") 60 | light.SetState(NewYellow()) 61 | } 62 | 63 | // 转换为红灯 64 | func (r *Red) ToRed(light *TrafficLight) { 65 | fmt.Println("错误,已经是红灯!") 66 | } 67 | 68 | // 定义一个黄灯 69 | type Yellow struct{} 70 | 71 | // 创建一个黄灯实例 72 | func NewYellow() *Yellow { 73 | return &Yellow{} 74 | } 75 | 76 | // 转换为绿灯 77 | func (y Yellow) ToGreen(light *TrafficLight) { 78 | fmt.Println("绿灯亮起 5 秒!") 79 | light.SetState(NewGreen()) 80 | } 81 | 82 | // 转换为黄灯 83 | func (y Yellow) ToYellow(light *TrafficLight) { 84 | fmt.Println("错误,已经是黄灯!") 85 | } 86 | 87 | // 转换为红灯 88 | func (y Yellow) ToRed(light *TrafficLight) { 89 | fmt.Println("红灯亮起 5 秒!") 90 | light.SetState(NewRed()) 91 | } 92 | 93 | // 定义一个绿灯 94 | type Green struct{} 95 | 96 | // 创建一个绿灯实例 97 | func NewGreen() *Green { 98 | return &Green{} 99 | } 100 | 101 | // 转换为绿灯 102 | func (g *Green) ToGreen(light *TrafficLight) { 103 | fmt.Println("错误,已经是绿灯!") 104 | } 105 | 106 | // 转换为黄灯 107 | func (g *Green) ToYellow(light *TrafficLight) { 108 | fmt.Println("黄灯亮起 5 秒!") 109 | light.SetState(NewYellow()) 110 | } 111 | 112 | // 转换为红灯 113 | func (g *Green) ToRed(light *TrafficLight) { 114 | fmt.Println("红灯亮起 5 秒!") 115 | light.SetState(NewRed()) 116 | } 117 | -------------------------------------------------------------------------------- /behavioral/state/state_test.go: -------------------------------------------------------------------------------- 1 | package state 2 | 3 | func ExampleState() { 4 | traffic := NewTrafficLight() 5 | traffic.ToYellow() 6 | traffic.ToGreen() 7 | traffic.ToRed() 8 | // Output: 9 | // 黄灯亮起 5 秒! 10 | // 绿灯亮起 5 秒! 11 | // 红灯亮起 5 秒! 12 | } 13 | -------------------------------------------------------------------------------- /behavioral/strategy/README.md: -------------------------------------------------------------------------------- 1 | ## 策略模式 2 | 3 | 策略模式(Strategy Pattern)定义了一系列算法,将每个算法封装起来,并使它们可以互相替换。客户端可以在运行时动态地选择需要的算法。 4 | -------------------------------------------------------------------------------- /behavioral/strategy/strategy.go: -------------------------------------------------------------------------------- 1 | package strategy 2 | 3 | // 策略模式 4 | 5 | // 定义一个策略类 6 | type IStrategy interface { 7 | Do(int, int) int 8 | } 9 | 10 | // 策略实现:加 11 | type Add struct{} 12 | 13 | func (*Add) Do(a, b int) int { 14 | return a + b 15 | } 16 | 17 | // 策略实现:减 18 | type Reduce struct{} 19 | 20 | func (*Reduce) Do(a, b int) int { 21 | return a - b 22 | } 23 | 24 | // 具体策略的执行者 25 | type Operator struct { 26 | strategy IStrategy 27 | } 28 | 29 | // 设置策略 30 | func (o *Operator) SetStrategy(strategy IStrategy) { 31 | o.strategy = strategy 32 | } 33 | 34 | // 调用策略中的方法 35 | func (o *Operator) Calculate(a, b int) int { 36 | return o.strategy.Do(a, b) 37 | } 38 | 39 | func NewOperator(strategy IStrategy) *Operator { 40 | return &Operator{strategy: strategy} 41 | } 42 | -------------------------------------------------------------------------------- /behavioral/strategy/strategy_test.go: -------------------------------------------------------------------------------- 1 | package strategy 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func ExampleStrategy() { 8 | operator := NewOperator(&Add{}) 9 | result := operator.Calculate(1, 2) 10 | fmt.Println("Do add:", result) 11 | 12 | operator.SetStrategy(&Reduce{}) 13 | result = operator.Calculate(2, 1) 14 | fmt.Println("Do reduce:", result) 15 | // Output: 16 | // Do add: 3 17 | // Do reduce: 1 18 | } 19 | -------------------------------------------------------------------------------- /behavioral/templatemethod/README.md: -------------------------------------------------------------------------------- 1 | ## 模板方法模式 2 | 3 | 模板方法模式(Template Method Pattern)是对多种事物的结构、形式、行为的模式化总结,而模板方法模式(Template Method)则是对一系列类行为(方法)的模式化。我们将总结出来的行为规律固化在基类中,对具体的行为实现则进行抽象化并交给子类去完成,如此便实现了子类对基类模板的套用。 4 | -------------------------------------------------------------------------------- /behavioral/templatemethod/example/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Cooker interface { 6 | fire() 7 | cooke() 8 | outfire() 9 | } 10 | 11 | // 类似于一个抽象类 12 | type CookMenu struct { 13 | } 14 | 15 | func (CookMenu) fire() { 16 | fmt.Println("开火") 17 | } 18 | 19 | // 做菜,交给具体的子类实现 20 | func (CookMenu) cooke() { 21 | } 22 | 23 | func (CookMenu) outfire() { 24 | fmt.Println("关火") 25 | } 26 | 27 | // 封装具体步骤 28 | func doCook(cook Cooker) { 29 | cook.fire() 30 | cook.cooke() 31 | cook.outfire() 32 | } 33 | 34 | type XiHongShi struct { 35 | CookMenu 36 | } 37 | 38 | func (*XiHongShi) cooke() { 39 | fmt.Println("做西红柿") 40 | } 41 | 42 | type ChaoJiDan struct { 43 | CookMenu 44 | } 45 | 46 | func (ChaoJiDan) cooke() { 47 | fmt.Println("做炒鸡蛋") 48 | } 49 | 50 | func main() { 51 | // 做西红柿 52 | xihongshi := &XiHongShi{} 53 | doCook(xihongshi) 54 | 55 | fmt.Println("\n=====> 做另外一道菜") 56 | // 做炒鸡蛋 57 | chaojidan := &ChaoJiDan{} 58 | doCook(chaojidan) 59 | 60 | } 61 | -------------------------------------------------------------------------------- /behavioral/templatemethod/templatemethod.go: -------------------------------------------------------------------------------- 1 | package templatemethod 2 | 3 | import "fmt" 4 | 5 | // 抽象方法 6 | type Milker interface { 7 | // 选择材料 8 | SelectBean() 9 | // 浸泡 10 | Soak() 11 | // 榨汁 12 | Beat() 13 | // 添加配料,子类实现 14 | AddCondiment() 15 | } 16 | 17 | // 基类 18 | type SoyaMilk struct{} 19 | 20 | func (s *SoyaMilk) SelectBean() { 21 | fmt.Println("第 1 步:选择新鲜的豆子") 22 | } 23 | 24 | func (s *SoyaMilk) AddCondiment() {} 25 | 26 | func (s *SoyaMilk) Soak() { 27 | fmt.Println("第 3 步:豆子和配料开始浸泡 3H") 28 | } 29 | 30 | func (s *SoyaMilk) Beat() { 31 | fmt.Println("第 4 步:豆子和配料放入豆浆机榨汁") 32 | } 33 | 34 | type RedBeanSoyaMilk struct { 35 | SoyaMilk 36 | } 37 | 38 | func NewRedBeanSoyaMilk() *RedBeanSoyaMilk { 39 | return &RedBeanSoyaMilk{} 40 | } 41 | 42 | func (r *RedBeanSoyaMilk) AddCondiment() { 43 | fmt.Println("第 2 步:加入上好的红豆") 44 | } 45 | 46 | type PeanutSoyaMilk struct { 47 | SoyaMilk 48 | } 49 | 50 | func NewPeanutSoyaMilk() *PeanutSoyaMilk { 51 | return &PeanutSoyaMilk{} 52 | } 53 | 54 | func (p *PeanutSoyaMilk) AddCondiment() { 55 | fmt.Println("第 2 步:加入上好的花生") 56 | } 57 | 58 | // 模版方法 59 | func DoMake(milk Milker) { 60 | milk.SelectBean() 61 | milk.AddCondiment() 62 | milk.Soak() 63 | milk.Beat() 64 | } 65 | -------------------------------------------------------------------------------- /behavioral/templatemethod/templatemethod_test.go: -------------------------------------------------------------------------------- 1 | package templatemethod 2 | 3 | import "fmt" 4 | 5 | func ExampleTemplateMethod() { 6 | fmt.Println("=======制作红豆豆浆=======") 7 | redBeanSoyaMilk := NewRedBeanSoyaMilk() 8 | DoMake(redBeanSoyaMilk) 9 | fmt.Println("=======制作花生豆浆=======") 10 | peanutSoyaMilk := NewPeanutSoyaMilk() 11 | DoMake(peanutSoyaMilk) 12 | // Output: 13 | // =======制作红豆豆浆======= 14 | // 第 1 步:选择新鲜的豆子 15 | // 第 2 步:加入上好的红豆 16 | // 第 3 步:豆子和配料开始浸泡 3H 17 | // 第 4 步:豆子和配料放入豆浆机榨汁 18 | // =======制作花生豆浆======= 19 | // 第 1 步:选择新鲜的豆子 20 | // 第 2 步:加入上好的花生 21 | // 第 3 步:豆子和配料开始浸泡 3H 22 | // 第 4 步:豆子和配料放入豆浆机榨汁 23 | } 24 | -------------------------------------------------------------------------------- /behavioral/visitor/README.md: -------------------------------------------------------------------------------- 1 | ## 访问者模式 2 | 3 | 访问者模式(Visitor Pattern)允许你定义一些操作,可以应用于一个对象结构的元素,而不会改变类。这使得可以在不改变元素类的情况下,新建操作并对其应用于元素类。访问者模式能够使得执行的操作独立于对象结构,同时也增加了在结构上增加新操作的灵活性。 4 | -------------------------------------------------------------------------------- /behavioral/visitor/visitor.go: -------------------------------------------------------------------------------- 1 | package visitor 2 | 3 | import "fmt" 4 | 5 | // 抽象访问者接口 6 | type Visitor interface { 7 | // 参观猎豹馆 8 | VisitLeopardSpot(leopard *LeopardSpot) 9 | // 参观海豚馆 10 | VisitDolphinSpot(dolphin *DolphinSpot) 11 | } 12 | 13 | // 场馆景点 14 | type Scenery interface { 15 | // 接待访问者 16 | Accept(visitor Visitor) 17 | // 票价 18 | Price() int 19 | } 20 | 21 | // 定义一个动物园 22 | type Zoo struct { 23 | // 动物园包含多个景点 24 | Sceneries []Scenery 25 | } 26 | 27 | // 创建一个动物园 28 | func NewZoo() *Zoo { 29 | return &Zoo{} 30 | } 31 | 32 | // 给动物园添加景点 33 | func (z *Zoo) Add(scenery Scenery) { 34 | z.Sceneries = append(z.Sceneries, scenery) 35 | } 36 | 37 | // 动物园接待游客 38 | func (z *Zoo) Accept(v Visitor) { 39 | for _, scenery := range z.Sceneries { 40 | scenery.Accept(v) 41 | } 42 | } 43 | 44 | // 豹子馆 45 | type LeopardSpot struct{} 46 | 47 | func (l *LeopardSpot) Accept(visitor Visitor) { 48 | visitor.VisitLeopardSpot(l) 49 | } 50 | 51 | // 票价15元 52 | func (l *LeopardSpot) Price() int { 53 | return 15 54 | } 55 | 56 | // 海豚馆 57 | type DolphinSpot struct{} 58 | 59 | func NewDolphinSpot() *DolphinSpot { 60 | return &DolphinSpot{} 61 | } 62 | 63 | func (d *DolphinSpot) Accept(visitor Visitor) { 64 | visitor.VisitDolphinSpot(d) 65 | } 66 | 67 | func (d *DolphinSpot) Price() int { 68 | return 15 69 | } 70 | 71 | // 学生的访问游客 72 | type StudentVisitor struct{} 73 | 74 | func NewStudentVisitor() *StudentVisitor { 75 | return &StudentVisitor{} 76 | } 77 | 78 | func (s *StudentVisitor) VisitLeopardSpot(leopard *LeopardSpot) { 79 | fmt.Printf("学生游客游览豹子馆票价: %v\n", leopard.Price()/2) 80 | } 81 | 82 | func (s *StudentVisitor) VisitDolphinSpot(dolphin *DolphinSpot) { 83 | fmt.Printf("学生游客游览海豚馆票价: %v\n", dolphin.Price()/2) 84 | } 85 | 86 | // 普通游客的访问游客 87 | type CommonVisitor struct{} 88 | 89 | func NewCommonVisitor() *CommonVisitor { 90 | return &CommonVisitor{} 91 | } 92 | 93 | func (c *CommonVisitor) VisitLeopardSpot(leopard *LeopardSpot) { 94 | fmt.Printf("普通游客游览豹子馆票价: %v\n", leopard.Price()) 95 | } 96 | 97 | func (c *CommonVisitor) VisitDolphinSpot(dolphin *DolphinSpot) { 98 | fmt.Printf("普通游客游览海豚馆票价: %v\n", dolphin.Price()) 99 | } 100 | -------------------------------------------------------------------------------- /behavioral/visitor/visitor_test.go: -------------------------------------------------------------------------------- 1 | package visitor 2 | 3 | func ExampleVisitor() { 4 | // 创建动物园 5 | zoo := NewZoo() 6 | 7 | // 添加场景 8 | zoo.Add(NewDolphinSpot()) 9 | zoo.Add(NewDolphinSpot()) 10 | 11 | // 访问场景 12 | zoo.Accept(NewStudentVisitor()) 13 | zoo.Accept(NewCommonVisitor()) 14 | // Output: 15 | // 学生游客游览海豚馆票价: 7 16 | // 学生游客游览海豚馆票价: 7 17 | // 普通游客游览海豚馆票价: 15 18 | // 普通游客游览海豚馆票价: 15 19 | } 20 | -------------------------------------------------------------------------------- /concurrency/barrier/README.md: -------------------------------------------------------------------------------- 1 | ## 屏障模式 2 | 3 | 屏障模式(N-Barrier Pattern)用于在多个并行任务中实现一组任务的同步。该模式将多个任务执行到一个屏障(Barrier)上,等待所有任务都到达后,再一起继续执行。N-Barrier 模式中的 N 表示需要等待的任务数量。当所有 N 个任务都到达屏障时,它们可以同时继续执行。 4 | -------------------------------------------------------------------------------- /concurrency/barrier/barrier.go: -------------------------------------------------------------------------------- 1 | package barrier 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func Worker(id int, barrier *sync.WaitGroup) { 9 | defer barrier.Done() // 每个任务完成时标记 Done 10 | 11 | fmt.Printf("Worker %d starts\n", id) 12 | // 模拟任务执行 13 | for i := 0; i < 3; i++ { 14 | fmt.Printf("Worker %d is working\n", id) 15 | } 16 | fmt.Printf("Worker %d finishes\n", id) 17 | } 18 | -------------------------------------------------------------------------------- /concurrency/barrier/barrier_test.go: -------------------------------------------------------------------------------- 1 | package barrier 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | func TestNBarrier(t *testing.T) { 10 | var barrier sync.WaitGroup 11 | numWorkers := 3 // 设定任务数量为 3 12 | 13 | // 设置等待的任务数量 14 | barrier.Add(numWorkers) 15 | 16 | // 启动多个 Goroutines 执行任务 17 | for i := 0; i < numWorkers; i++ { 18 | go Worker(i, &barrier) 19 | } 20 | 21 | // 等待所有任务完成 22 | barrier.Wait() 23 | 24 | fmt.Println("All workers have finished, continue to the next step") 25 | } 26 | -------------------------------------------------------------------------------- /concurrency/batcher/README.md: -------------------------------------------------------------------------------- 1 | ## 批处理模式 2 | 3 | 批处理模式(Batch Processing Pattern)用于处理大量数据或任务的情况下,将多个操作合并成一个批次进行处理,以提高效率和性能。批处理模式适用于需要对大量数据进行相似操作或需要批量处理任务的场景,可以有效减少系统开销和资源消耗。 4 | -------------------------------------------------------------------------------- /concurrency/batcher/batcher.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | const batchSize = 5 9 | 10 | func processBatch(data []int) { 11 | fmt.Println("Processing batch:", data) 12 | // 模拟处理数据的逻辑 13 | time.Sleep(2 * time.Second) 14 | } 15 | 16 | func main() { 17 | data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 18 | totalData := len(data) 19 | 20 | for i := 0; i < totalData; i += batchSize { 21 | end := i + batchSize 22 | if end > totalData { 23 | end = totalData 24 | } 25 | batch := data[i:end] 26 | go processBatch(batch) // 并发处理批次数据 27 | } 28 | 29 | time.Sleep(3 * time.Second) // 等待异步处理完成 30 | fmt.Println("All batches processed.") 31 | } 32 | -------------------------------------------------------------------------------- /concurrency/batcher/example/README.md: -------------------------------------------------------------------------------- 1 | # 批处理模式 2 | 3 | The batching resiliency pattern for golang. 4 | 5 | Creating a batcher takes two parameters: 6 | - the timeout to wait while collecting a batch 7 | - the function to run once a batch has been collected 8 | 9 | You can also optionally set a prefilter to fail queries before they enter the 10 | batch. 11 | 12 | ```go 13 | b := batcher.New(10*time.Millisecond, func(params []interface{}) error { 14 | // do something with the batch of parameters 15 | return nil 16 | }) 17 | 18 | b.Prefilter(func(param interface{}) error { 19 | // do some sort of sanity check on the parameter, and return an error if it fails 20 | return nil 21 | }) 22 | 23 | for i := 0; i < 10; i++ { 24 | go b.Run(i) 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /concurrency/batcher/example/batcher.go: -------------------------------------------------------------------------------- 1 | // Package batcher implements the batching resiliency pattern for Go. 2 | package batcher 3 | 4 | import ( 5 | "sync" 6 | "time" 7 | ) 8 | 9 | type work struct { 10 | param interface{} 11 | future chan error 12 | } 13 | 14 | // Batcher implements the batching resiliency pattern 15 | type Batcher struct { 16 | timeout time.Duration 17 | prefilter func(interface{}) error 18 | 19 | lock sync.Mutex 20 | submit chan *work 21 | doWork func([]interface{}) error 22 | } 23 | 24 | // New constructs a new batcher that will batch all calls to Run that occur within 25 | // `timeout` time before calling doWork just once for the entire batch. The doWork 26 | // function must be safe to run concurrently with itself as this may occur, especially 27 | // when the timeout is small. 28 | func New(timeout time.Duration, doWork func([]interface{}) error) *Batcher { 29 | return &Batcher{ 30 | timeout: timeout, 31 | doWork: doWork, 32 | } 33 | } 34 | 35 | // Run runs the work function with the given parameter, possibly 36 | // including it in a batch with other calls to Run that occur within the 37 | // specified timeout. It is safe to call Run concurrently on the same batcher. 38 | func (b *Batcher) Run(param interface{}) error { 39 | if b.prefilter != nil { 40 | if err := b.prefilter(param); err != nil { 41 | return err 42 | } 43 | } 44 | 45 | if b.timeout == 0 { 46 | return b.doWork([]interface{}{param}) 47 | } 48 | 49 | w := &work{ 50 | param: param, 51 | future: make(chan error, 1), 52 | } 53 | 54 | b.submitWork(w) 55 | 56 | return <-w.future 57 | } 58 | 59 | // Prefilter specifies an optional function that can be used to run initial checks on parameters 60 | // passed to Run before being added to the batch. If the prefilter returns a non-nil error, 61 | // that error is returned immediately from Run and the batcher is not invoked. A prefilter 62 | // cannot safely be specified for a batcher if Run has already been invoked. The filter function 63 | // specified must be concurrency-safe. 64 | func (b *Batcher) Prefilter(filter func(interface{}) error) { 65 | b.prefilter = filter 66 | } 67 | 68 | func (b *Batcher) submitWork(w *work) { 69 | b.lock.Lock() 70 | defer b.lock.Unlock() 71 | 72 | if b.submit == nil { 73 | b.submit = make(chan *work, 4) 74 | go b.batch() 75 | } 76 | 77 | b.submit <- w 78 | } 79 | 80 | func (b *Batcher) batch() { 81 | var params []interface{} 82 | var futures []chan error 83 | input := b.submit 84 | 85 | go b.timer() 86 | 87 | for work := range input { 88 | params = append(params, work.param) 89 | futures = append(futures, work.future) 90 | } 91 | 92 | ret := b.doWork(params) 93 | 94 | for _, future := range futures { 95 | future <- ret 96 | close(future) 97 | } 98 | } 99 | 100 | func (b *Batcher) timer() { 101 | time.Sleep(b.timeout) 102 | 103 | b.lock.Lock() 104 | defer b.lock.Unlock() 105 | 106 | close(b.submit) 107 | b.submit = nil 108 | } 109 | -------------------------------------------------------------------------------- /concurrency/batcher/example/batcher_test.go: -------------------------------------------------------------------------------- 1 | package batcher 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | "sync/atomic" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | var errSomeError = errors.New("errSomeError") 12 | 13 | func returnsError(params []interface{}) error { 14 | return errSomeError 15 | } 16 | 17 | func returnsSuccess(params []interface{}) error { 18 | return nil 19 | } 20 | 21 | func TestBatcherSuccess(t *testing.T) { 22 | b := New(10*time.Millisecond, returnsSuccess) 23 | 24 | wg := &sync.WaitGroup{} 25 | for i := 0; i < 10; i++ { 26 | wg.Add(1) 27 | go func() { 28 | if err := b.Run(nil); err != nil { 29 | t.Error(err) 30 | } 31 | wg.Done() 32 | }() 33 | } 34 | wg.Wait() 35 | 36 | b = New(0, returnsSuccess) 37 | for i := 0; i < 10; i++ { 38 | if err := b.Run(nil); err != nil { 39 | t.Error(err) 40 | } 41 | } 42 | } 43 | 44 | func TestBatcherError(t *testing.T) { 45 | b := New(10*time.Millisecond, returnsError) 46 | 47 | wg := &sync.WaitGroup{} 48 | for i := 0; i < 10; i++ { 49 | wg.Add(1) 50 | go func() { 51 | if err := b.Run(nil); err != errSomeError { 52 | t.Error(err) 53 | } 54 | wg.Done() 55 | }() 56 | } 57 | wg.Wait() 58 | } 59 | 60 | func TestBatcherPrefilter(t *testing.T) { 61 | b := New(1*time.Millisecond, returnsSuccess) 62 | 63 | b.Prefilter(func(param interface{}) error { 64 | if param == nil { 65 | return errSomeError 66 | } 67 | return nil 68 | }) 69 | 70 | if err := b.Run(nil); err != errSomeError { 71 | t.Error(err) 72 | } 73 | 74 | if err := b.Run(1); err != nil { 75 | t.Error(err) 76 | } 77 | } 78 | 79 | func TestBatcherMultipleBatches(t *testing.T) { 80 | var iters uint32 81 | 82 | b := New(10*time.Millisecond, func(params []interface{}) error { 83 | atomic.AddUint32(&iters, 1) 84 | return nil 85 | }) 86 | 87 | wg := &sync.WaitGroup{} 88 | 89 | for group := 0; group < 5; group++ { 90 | for i := 0; i < 10; i++ { 91 | wg.Add(1) 92 | go func() { 93 | if err := b.Run(nil); err != nil { 94 | t.Error(err) 95 | } 96 | wg.Done() 97 | }() 98 | } 99 | time.Sleep(15 * time.Millisecond) 100 | } 101 | 102 | wg.Wait() 103 | 104 | if iters != 5 { 105 | t.Error("Wrong number of iters:", iters) 106 | } 107 | } 108 | 109 | func ExampleBatcher() { 110 | b := New(10*time.Millisecond, func(params []interface{}) error { 111 | // do something with the batch of parameters 112 | return nil 113 | }) 114 | 115 | b.Prefilter(func(param interface{}) error { 116 | // do some sort of sanity check on the parameter, and return an error if it fails 117 | return nil 118 | }) 119 | 120 | for i := 0; i < 10; i++ { 121 | go b.Run(i) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /concurrency/boundedparallelism/README.md: -------------------------------------------------------------------------------- 1 | ## 有界并行性模式 2 | 3 | 有界并行性模式(Bounded Parallelism Pattern)用于控制并发执行任务的数量,避免系统资源被过度占用。该模式限制在同时执行的任务数量,可以有效控制并发度,避免系统过载。在 Bounded Parallelism 模式中,任务被分成多个批次,每个批次内可以同时执行的任务数量是有限的,超过限制的任务会等待前面任务完成后再执行。 4 | -------------------------------------------------------------------------------- /concurrency/boundedparallelism/bounded_parallelism.go: -------------------------------------------------------------------------------- 1 | package boundedparallelism 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func Worker(id int, semaphore chan struct{}) { 9 | semaphore <- struct{}{} // 占用一个信号 10 | defer func() { <-semaphore }() // 释放信号 11 | 12 | // 模拟任务执行 13 | fmt.Printf("Worker %d is working\n", id) 14 | time.Sleep(2 * time.Second) 15 | } 16 | -------------------------------------------------------------------------------- /concurrency/boundedparallelism/bounded_parallelism_test.go: -------------------------------------------------------------------------------- 1 | package boundedparallelism 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | func TestBoundedParallelism(t *testing.T) { 10 | numWorkers := 5 11 | boundedParallelism := 2 12 | semaphore := make(chan struct{}, boundedParallelism) 13 | 14 | var wg sync.WaitGroup 15 | wg.Add(numWorkers) 16 | 17 | for i := 0; i < numWorkers; i++ { 18 | go func(id int) { 19 | defer wg.Done() 20 | Worker(id, semaphore) 21 | }(i) 22 | } 23 | 24 | wg.Wait() 25 | 26 | fmt.Println("All workers have finished, continue to the next step") 27 | } 28 | -------------------------------------------------------------------------------- /concurrency/broadcast/README.md: -------------------------------------------------------------------------------- 1 | ## 广播模式 2 | 3 | 广播模式(Broadcast Pattern)是一种发布-订阅设计模式,用于在系统中广播消息或事件给多个接收者。在 Broadcast 模式中,一个消息或事件可以同时传递给多个订阅者,让它们独立处理。这种模式适用于需要消息广播给多个接收者的场景,提高系统的扩展性和灵活性。 4 | -------------------------------------------------------------------------------- /concurrency/broadcast/broadcast.go: -------------------------------------------------------------------------------- 1 | package broadcast 2 | 3 | func Broadcaster(message string, receivers []chan string) { 4 | for _, receiver := range receivers { 5 | receiver <- message // 将消息发送给每个接收者 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /concurrency/broadcast/broadcast_test.go: -------------------------------------------------------------------------------- 1 | package broadcast 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestBroadcast(t *testing.T) { 9 | receivers := make([]chan string, 3) 10 | 11 | // 创建三个接收者 Channel 12 | for i := range receivers { 13 | receivers[i] = make(chan string) 14 | } 15 | 16 | // 启动多个 Goroutines 作为接收者 17 | for i := range receivers { 18 | go func(id int, receiver chan string) { 19 | for { 20 | message := <-receiver // 接收消息 21 | fmt.Printf("Receiver %d got: %s\n", id, message) 22 | } 23 | }(i, receivers[i]) 24 | } 25 | 26 | message := "Hello, this is a broadcast message" 27 | Broadcaster(message, receivers) 28 | 29 | // 等待一段时间 30 | select {} 31 | } 32 | -------------------------------------------------------------------------------- /concurrency/coroutines/README.md: -------------------------------------------------------------------------------- 1 | ## 协程模式 2 | 3 | 协程模式(Coroutines Pattern)通过轻量级的执行单元(Coroutines)实现并发操作。在 Go 语言中,Goroutines 是实现 Coroutines 模式的核心机制。Goroutines 是 Go 语言中轻量级的并发执行单元,允许在程序中创建多个独立的执行流,这些执行流可以在程序执行过程中相互协作,而无需显式处理线程管理和同步问题。 4 | -------------------------------------------------------------------------------- /concurrency/coroutines/coroutines.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func printNumbers() { 9 | for i := 1; i <= 5; i++ { 10 | time.Sleep(time.Second) // 模拟耗时操作 11 | fmt.Printf("Goroutine 1: %d\n", i) 12 | } 13 | } 14 | 15 | func printLetters() { 16 | for i := 'A'; i <= 'E'; i++ { 17 | time.Sleep(time.Second) // 模拟耗时操作 18 | fmt.Printf("Goroutine 2: %c\n", i) 19 | } 20 | } 21 | 22 | func main() { 23 | go printNumbers() // 启动第一个 Goroutine 24 | go printLetters() // 启动第二个 Goroutine 25 | 26 | time.Sleep(4 * time.Second) // 等待 Goroutines 执行完成 27 | fmt.Println("Main Goroutine exits") 28 | } 29 | -------------------------------------------------------------------------------- /concurrency/generator/README.md: -------------------------------------------------------------------------------- 1 | ## 生成器模式 2 | 3 | 生成器模式(Generator Pattern)允许按需生成序列数据,而不是一次性生成所有数据。这种惰性生成数据的方式可以节省内存和提高性能。在 Go 语言中,可以使用 Generators 模式生成数据流,并在需要时逐个获取数据。 4 | -------------------------------------------------------------------------------- /concurrency/generator/generator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func fibonacci(n int) <-chan int { 6 | ch := make(chan int) 7 | 8 | go func() { 9 | defer close(ch) 10 | a, b := 0, 1 11 | for i := 0; i < n; i++ { 12 | ch <- a 13 | a, b = b, a+b 14 | } 15 | }() 16 | 17 | return ch 18 | } 19 | 20 | func main() { 21 | fibCh := fibonacci(5) 22 | 23 | for num := range fibCh { 24 | fmt.Println(num) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /concurrency/parallelism/README.md: -------------------------------------------------------------------------------- 1 | ## 并行模式 2 | 3 | 并行模式(Parallelism Pattern)是一种设计模式,旨在有效利用多核处理器并行执行任务,以提高程序的性能和效率。 4 | -------------------------------------------------------------------------------- /concurrency/parallelism/parallelism.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func fibonacci(n int, c chan int) { 9 | x, y := 0, 1 10 | for i := 0; i < n; i++ { 11 | c <- x 12 | x, y = y, x+y 13 | } 14 | close(c) 15 | } 16 | 17 | func main() { 18 | startTime := time.Now() 19 | 20 | c := make(chan int) 21 | go fibonacci(15, c) 22 | 23 | for num := range c { 24 | fmt.Print(num, " ") 25 | } 26 | 27 | endTime := time.Now() 28 | elapsedTime := endTime.Sub(startTime) 29 | fmt.Printf("\nTotal time taken: %s\n", elapsedTime) 30 | } 31 | -------------------------------------------------------------------------------- /concurrency/producerconsumer/README.md: -------------------------------------------------------------------------------- 1 | ## 生产者消费者模式 2 | 3 | 生产者消费者模式(Producer Consumer Pattern)用于解决生产者和消费者之间的协作问题。在这种模式中,生产者负责生产数据并放入共享的队列中,而消费者则从队列中取出数据进行处理。 4 | -------------------------------------------------------------------------------- /concurrency/producerconsumer/producerconsumer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func producer(queue chan int) { 9 | for i := 0; i < 5; i++ { 10 | time.Sleep(time.Second) 11 | fmt.Println("Producing data:", i) 12 | queue <- i 13 | } 14 | close(queue) 15 | } 16 | 17 | func consumer(queue chan int) { 18 | for data := range queue { 19 | fmt.Println("Consuming data:", data) 20 | } 21 | } 22 | 23 | func main() { 24 | queue := make(chan int) 25 | 26 | go producer(queue) 27 | go consumer(queue) 28 | 29 | time.Sleep(6 * time.Second) 30 | } 31 | -------------------------------------------------------------------------------- /concurrency/reactor/README.md: -------------------------------------------------------------------------------- 1 | ## 反应器模式 2 | 3 | 反应器模式(Reactor Pattern)是一种事件驱动设计模式,用于处理并发的 I/O 操作。在 Reactor 模式中,事件循环(Event Loop)负责监听事件并根据事件类型调用相应的处理程序。 4 | -------------------------------------------------------------------------------- /concurrency/reactor/reactor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | func handleConnection(conn net.Conn) { 9 | defer conn.Close() 10 | 11 | fmt.Println("Client connected:", conn.RemoteAddr()) 12 | 13 | // 处理客户端请求 14 | // 这里简单回显客户端发送的消息 15 | buffer := make([]byte, 1024) 16 | for { 17 | n, err := conn.Read(buffer) 18 | if err != nil { 19 | fmt.Println("Error reading:", err) 20 | return 21 | } 22 | fmt.Println("Received message:", string(buffer[:n])) 23 | _, err = conn.Write(buffer[:n]) 24 | if err != nil { 25 | fmt.Println("Error writing:", err) 26 | return 27 | } 28 | } 29 | } 30 | 31 | func main() { 32 | listener, err := net.Listen("tcp", ":8080") 33 | if err != nil { 34 | fmt.Println("Error listening:", err) 35 | return 36 | } 37 | defer listener.Close() 38 | fmt.Println("Server listening on :8080") 39 | 40 | for { 41 | conn, err := listener.Accept() 42 | if err != nil { 43 | fmt.Println("Error accepting connection:", err) 44 | continue 45 | } 46 | go handleConnection(conn) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /creational/abstractfactory/README.md: -------------------------------------------------------------------------------- 1 | ## 抽象工厂模式 2 | 3 | 抽象工厂模式(Abstract Factory Pattern)提供了一个接口用于创建一系列相关对象。这些对象构成一个产品族,而不需要指定具体的类。抽象工厂模式适用于需要创建多个相互关联的对象,使得系统独立于具体产品类,同时提供了易于扩展和替换的能力。 4 | -------------------------------------------------------------------------------- /creational/abstractfactory/abstractfactory.go: -------------------------------------------------------------------------------- 1 | package abstractfactory 2 | 3 | import "fmt" 4 | 5 | // DoorFactory 是抽象工厂接口,定义了创建门和门把手的方法 6 | type DoorFactory interface { 7 | CreateDoor() Door 8 | CreateDoorHandle() DoorHandle 9 | } 10 | 11 | // Door 是门接口 12 | type Door interface { 13 | Open() 14 | Close() 15 | } 16 | 17 | // DoorHandle 是门把手接口 18 | type DoorHandle interface { 19 | Press() 20 | } 21 | 22 | // WoodenDoorFactory 是一个具体的木门工厂,实现了 DoorFactory 接口 23 | type WoodenDoorFactory struct{} 24 | 25 | func (f *WoodenDoorFactory) CreateDoor() Door { 26 | return &WoodenDoor{} 27 | } 28 | 29 | func (f *WoodenDoorFactory) CreateDoorHandle() DoorHandle { 30 | return &WoodenDoorHandle{} 31 | } 32 | 33 | // WoodenDoor 是木门实现 34 | type WoodenDoor struct{} 35 | 36 | func (d *WoodenDoor) Open() { 37 | fmt.Println("Wooden door is opened") 38 | } 39 | 40 | func (d *WoodenDoor) Close() { 41 | fmt.Println("Wooden door is closed") 42 | } 43 | 44 | // WoodenDoorHandle 是木门把手实现 45 | type WoodenDoorHandle struct{} 46 | 47 | func (h *WoodenDoorHandle) Press() { 48 | fmt.Println("Press wooden door handle") 49 | } 50 | -------------------------------------------------------------------------------- /creational/abstractfactory/abstractfactory_test.go: -------------------------------------------------------------------------------- 1 | package abstractfactory 2 | 3 | func ExampleAbstractFactory() { 4 | // 创建一个木门工厂 5 | woodenFactory := &WoodenDoorFactory{} 6 | 7 | // 使用木门工厂创建门和门把手 8 | door := woodenFactory.CreateDoor() 9 | doorHandle := woodenFactory.CreateDoorHandle() 10 | 11 | // 使用创建的门和门把手 12 | door.Open() 13 | doorHandle.Press() 14 | // Output: 15 | // Wooden door is opened 16 | // Press wooden door handle 17 | } 18 | -------------------------------------------------------------------------------- /creational/builder/README.md: -------------------------------------------------------------------------------- 1 | ## 建造者模式 2 | 3 | 建造者模式(Builder Pattern)返回给客户一个完整的的产品对象,而客户端无须关心该对象所包含的额外属性和组建方式,这就是建造者模式的设计动机。建造者模式将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。 4 | -------------------------------------------------------------------------------- /creational/builder/builder.go: -------------------------------------------------------------------------------- 1 | package builder 2 | 3 | import "fmt" 4 | 5 | // ICar 汽车,我们要造车了 6 | // ICar 车具有以下能力 7 | type ICar interface { 8 | Speed() int 9 | Brand() string 10 | Brief() 11 | } 12 | 13 | // ICarBuilder 造一辆车需要具有的部件 14 | type ICarBuilder interface { 15 | Wheel(wheel int) ICarBuilder 16 | Engine(engine string) ICarBuilder 17 | Speed(max int) ICarBuilder 18 | Brand(brand string) ICarBuilder 19 | Build() ICar 20 | } 21 | 22 | // CarProto 车的原型 23 | type CarProto struct { 24 | Wheel int 25 | Engine string 26 | MaxSpeed int 27 | BrandName string 28 | } 29 | 30 | // Speed 最大车速 31 | func (c *CarProto) Speed() int { 32 | return c.MaxSpeed 33 | } 34 | 35 | // Brand 车品牌 36 | func (c *CarProto) Brand() string { 37 | return c.BrandName 38 | } 39 | 40 | // Brief 简介 41 | func (c *CarProto) Brief() { 42 | fmt.Println("this is a cool car") 43 | fmt.Println("car wheel size: ", c.Wheel) 44 | fmt.Println("car MaxSpeed: ", c.MaxSpeed) 45 | fmt.Println("car Engine: ", c.Engine) 46 | } 47 | 48 | // CarStudio 打算通过成立造车实验室进行造车 49 | type CarStudio struct { 50 | prototype CarProto 51 | } 52 | 53 | // NewCarStudio 造车工作室 54 | func NewCarStudio() ICarBuilder { 55 | return &CarStudio{} 56 | } 57 | 58 | // Wheel of car 59 | func (c *CarStudio) Wheel(wheel int) ICarBuilder { 60 | c.prototype.Wheel = wheel 61 | return c 62 | } 63 | 64 | // Engine of car 65 | func (c *CarStudio) Engine(engine string) ICarBuilder { 66 | c.prototype.Engine = engine 67 | return c 68 | } 69 | 70 | // Speed of car 71 | func (c *CarStudio) Speed(max int) ICarBuilder { 72 | c.prototype.MaxSpeed = max 73 | return c 74 | } 75 | 76 | // Brand of car 77 | func (c *CarStudio) Brand(brand string) ICarBuilder { 78 | c.prototype.BrandName = brand 79 | return c 80 | } 81 | 82 | // Build return a car 83 | func (c *CarStudio) Build() ICar { 84 | car := &CarProto{ 85 | Wheel: c.prototype.Wheel, 86 | Engine: c.prototype.Engine, 87 | MaxSpeed: c.prototype.MaxSpeed, 88 | BrandName: c.prototype.BrandName, 89 | } 90 | 91 | return car 92 | } 93 | -------------------------------------------------------------------------------- /creational/builder/builder_test.go: -------------------------------------------------------------------------------- 1 | package builder 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestBuilderCar(t *testing.T) { 9 | builder := NewCarStudio() 10 | builder.Brand("sky").Speed(120).Engine("audi") 11 | car := builder.Build() 12 | if car.Speed() != 120 { 13 | t.Fatalf("Builder1 fail expect 120 ,but get %d", car.Speed()) 14 | } 15 | if car.Brand() != "sky" { 16 | t.Fatalf("Builder1 fail expect sky ,but get %s", car.Brand()) 17 | } 18 | 19 | fmt.Println(car.Speed()) 20 | fmt.Println(car.Brand()) 21 | } 22 | 23 | func TestBuilderCarMore(t *testing.T) { 24 | builder := NewCarStudio() 25 | builder.Brand("land").Speed(110).Engine("bmw") 26 | builder.Engine("man made").Brand("panda").Wheel(15) 27 | car := builder.Build() 28 | 29 | fmt.Println(car.Speed()) 30 | fmt.Println(car.Brand()) 31 | car.Brief() 32 | } 33 | 34 | func ExampleBuilder() { 35 | builder := NewCarStudio() 36 | builder.Brand("land").Speed(110).Engine("bmw") 37 | builder.Engine("man made").Brand("panda").Wheel(15) 38 | car := builder.Build() 39 | 40 | fmt.Println(car.Speed()) 41 | fmt.Println(car.Brand()) 42 | car.Brief() 43 | // Output: 44 | // 110 45 | // panda 46 | // this is a cool car 47 | // car wheel size: 15 48 | // car MaxSpeed: 110 49 | // car Engine: man made 50 | } 51 | -------------------------------------------------------------------------------- /creational/factorymethod/README.md: -------------------------------------------------------------------------------- 1 | ## 工厂方法模式 2 | 3 | 工厂方法模式(Factory Method Pattern)定义了一个用于创建对象的接口,让子类决定实例化哪个类。这种模式通过定义一个工厂接口来创建对象,将对象的实例化延迟到子类的实现。 4 | -------------------------------------------------------------------------------- /creational/factorymethod/factorymethod.go: -------------------------------------------------------------------------------- 1 | package factorymethod 2 | 3 | import "fmt" 4 | 5 | // Logger 是日志记录器接口 6 | type Logger interface { 7 | Log(message string) 8 | } 9 | 10 | // FileLogger 是文件日志记录器实现 11 | type FileLogger struct{} 12 | 13 | func (f *FileLogger) Log(message string) { 14 | fmt.Println("Log to file: " + message) 15 | } 16 | 17 | // ConsoleLogger 是控制台日志记录器实现 18 | type ConsoleLogger struct{} 19 | 20 | func (c *ConsoleLogger) Log(message string) { 21 | fmt.Println("Log to console: " + message) 22 | } 23 | 24 | // LoggerFactory 是工厂方法接口,定义了创建日志记录器的方法 25 | type LoggerFactory interface { 26 | CreateLogger() Logger 27 | } 28 | 29 | // FileLoggerFactory 是文件日志记录器工厂实现 30 | type FileLoggerFactory struct{} 31 | 32 | func (f *FileLoggerFactory) CreateLogger() Logger { 33 | return &FileLogger{} 34 | } 35 | 36 | // ConsoleLoggerFactory 是控制台日志记录器工厂实现 37 | type ConsoleLoggerFactory struct{} 38 | 39 | func (c *ConsoleLoggerFactory) CreateLogger() Logger { 40 | return &ConsoleLogger{} 41 | } 42 | -------------------------------------------------------------------------------- /creational/factorymethod/factorymethod_test.go: -------------------------------------------------------------------------------- 1 | package factorymethod 2 | 3 | func ExampleFactoryMethod() { 4 | doLog(&FileLoggerFactory{}) 5 | doLog(&ConsoleLoggerFactory{}) 6 | // Output: 7 | // Log to file: This is a test log. 8 | // Log to console: This is a test log. 9 | } 10 | 11 | func doLog(factory LoggerFactory) { 12 | factory.CreateLogger().Log("This is a test log.") 13 | } 14 | -------------------------------------------------------------------------------- /creational/functionaloption/README.md: -------------------------------------------------------------------------------- 1 | ## 函数选项模式 2 | 3 | 函数选项模式(Functional Options Pattern)是一种常见的设计模式,用于处理函数或对象具有多个可选参数的情况。在Go语言中,选项模式通常通过函数选项(Function Options)的方式实现,允许用户根据需求为函数传递不同的选项参数,以定制函数的行为。这种模式在Go语言中非常灵活和常用,为函数调用提供了更多的灵活性和可定制性。 4 | -------------------------------------------------------------------------------- /creational/functionaloption/examples/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Options is key struct,关键数据结构,聚合所有外部可传入的参数 8 | type Options struct { 9 | UID int 10 | GID int 11 | Flags int 12 | Company string 13 | Gender bool //is male 14 | } 15 | 16 | // Option func is key func 17 | type Option func(*Options) 18 | 19 | // UID set User ID 20 | func UID(userID int) Option { 21 | return func(args *Options) { 22 | args.UID = userID 23 | } 24 | } 25 | 26 | // GID set User Group ID 27 | func GID(groupID int) Option { 28 | return func(args *Options) { 29 | args.GID = groupID 30 | } 31 | } 32 | 33 | // Company set Company Name 34 | func Company(cname string) Option { 35 | return func(args *Options) { 36 | args.Company = cname 37 | } 38 | } 39 | 40 | // Gender for male or female 41 | func Gender(gender bool) Option { 42 | return func(args *Options) { 43 | args.Gender = gender 44 | } 45 | } 46 | 47 | // Introduce someone 48 | func Introduce(name string, setters ...Option /*传入闭包设置函数*/) { 49 | // Default Options 50 | args := &Options{ 51 | UID: 0, 52 | GID: 0, 53 | Company: "", 54 | Gender: true, 55 | } 56 | //模式的重点体现在这里,通过外部传入的闭包函数设置内在变量 57 | for _, setter := range setters { 58 | setter(args) 59 | } 60 | gender := "famale" 61 | if args.Gender { 62 | gender = "male" 63 | } 64 | fmt.Println("----------------------") 65 | fmt.Println("im am: ", name, "\nfrom: ", args.Company, "\ngender: ", gender, "\nUID: ", args.UID) 66 | } 67 | 68 | func main() { 69 | Introduce("tom", Gender(true), Company("land company")) 70 | Introduce("lily", Company("sky commnay"), UID(123)) 71 | Introduce("admin", Company("risky commnay"), UID(883)) 72 | } 73 | -------------------------------------------------------------------------------- /creational/functionaloption/functionaloption.go: -------------------------------------------------------------------------------- 1 | package functionaloption 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | ) 7 | 8 | // HTTPClient 结构体表示HTTP客户端的配置选项 9 | type HTTPClient struct { 10 | Timeout time.Duration // Timeout 表示HTTP客户端等待响应的最大时间 11 | } 12 | 13 | // DefaultHTTPClient 函数返回HTTPClient的默认配置 14 | func DefaultHTTPClient() HTTPClient { 15 | return HTTPClient{ 16 | Timeout: 10 * time.Second, // 默认超时时间设置为10秒 17 | } 18 | } 19 | 20 | // Option 类型用于应用选项到HTTPClient 21 | type Option func(*HTTPClient) 22 | 23 | // WithTimeout 函数设置HTTPClient的超时时间 24 | func WithTimeout(timeout time.Duration) Option { 25 | return func(hc *HTTPClient) { 26 | hc.Timeout = timeout // 设置HTTP客户端的超时时间 27 | } 28 | } 29 | 30 | // NewHTTPClient 函数使用给定选项创建一个新的HTTP客户端 31 | func NewHTTPClient(opts ...Option) *http.Client { 32 | httpClient := DefaultHTTPClient() 33 | for _, opt := range opts { 34 | opt(&httpClient) 35 | } 36 | 37 | return &http.Client{ 38 | // 根据提供的选项设置HTTP客户端的超时时间 39 | Timeout: httpClient.Timeout, 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /creational/functionaloption/functionaloption_test.go: -------------------------------------------------------------------------------- 1 | package functionaloption 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func ExampleFunctionalOption() { 9 | // 使用自定义超时时间创建一个新的HTTP客户端 10 | client := NewHTTPClient(WithTimeout(5 * time.Second)) 11 | 12 | // 使用自定义HTTP客户端发起GET请求 13 | resp, err := client.Get("https://jsonplaceholder.typicode.com/posts/1") 14 | if err != nil { 15 | fmt.Println("Error:", err) 16 | return 17 | } 18 | defer resp.Body.Close() 19 | 20 | fmt.Println("Status Code:", resp.Status) 21 | // Output: 22 | // Status Code: 200 OK 23 | } 24 | -------------------------------------------------------------------------------- /creational/new/README.md: -------------------------------------------------------------------------------- 1 | ## New 模式 2 | 3 | New 模式(New Pattern)用于创建和初始化结构体实例。New 模式通常用于封装结构体的创建过程,提供一个包级函数或方法,用于统一实例化对象的方式,避免直接对外暴露结构体实例的构造细节。通过 New 模式,可以更好地封装对象的创建细节,提高代码的可读性和灵活性。 4 | -------------------------------------------------------------------------------- /creational/new/new.go: -------------------------------------------------------------------------------- 1 | package new 2 | 3 | // 示例模式:New 模式. 4 | 5 | // 定义 Product 结构体,用来代表一个商品. 6 | type Product struct { 7 | Name string 8 | Price float64 9 | } 10 | 11 | // Name 方法返回产品的名字. 12 | func (p *Product) GetName() string { 13 | return p.Name 14 | } 15 | 16 | // Price 方法返回产品的价格. 17 | func (p *Product) GetPrice() float64 { 18 | return p.Price 19 | } 20 | 21 | // 使用 NewProduct 创建并返回实例化后的实例,*Product 类型. 22 | func NewProduct(name string, price float64) *Product { 23 | return &Product{ 24 | Name: name, 25 | Price: price, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /creational/new/new_test.go: -------------------------------------------------------------------------------- 1 | package new 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestProductGetName(t *testing.T) { 10 | assert := assert.New(t) 11 | 12 | product := NewProduct("Laptop", 20.01) 13 | assert.Equal("Laptop", product.GetName()) 14 | } 15 | 16 | func TestProductGetPrice(t *testing.T) { 17 | assert := assert.New(t) 18 | 19 | product := NewProduct("Laptop", 20.01) 20 | assert.Equal(20.01, product.GetPrice()) 21 | } 22 | -------------------------------------------------------------------------------- /creational/objectpool/README.md: -------------------------------------------------------------------------------- 1 | ## 对象池模式 2 | 3 | 对象池模式(Object Pool Pattern)通过预先实例化一定数量的对象(对象池),在需要时从池中获取对象并在使用完成后将对象归还给池,减少了对象的创建和销毁次数,提高了系统的效率和性能。对象池一般包括初始化、对象获取、对象归还、资源释放等方法,确保对象的有效复用和管理。 4 | -------------------------------------------------------------------------------- /creational/objectpool/objectpool.go: -------------------------------------------------------------------------------- 1 | package objectpool 2 | 3 | // Object 表示对象池中的具体对象 4 | type Object struct { 5 | ID int 6 | } 7 | 8 | // ObjectPool 表示对象池,存储和管理对象 9 | type ObjectPool struct { 10 | objects chan *Object 11 | } 12 | 13 | // NewObjectPool 创建对象池并初始化对象 14 | func NewObjectPool(size int) *ObjectPool { 15 | pool := &ObjectPool{ 16 | objects: make(chan *Object, size), 17 | } 18 | for i := 0; i < size; i++ { 19 | object := &Object{ID: i} 20 | pool.objects <- object 21 | } 22 | return pool 23 | } 24 | 25 | // AcquireObject 从对象池中获取对象 26 | func (p *ObjectPool) AcquireObject() *Object { 27 | return <-p.objects 28 | } 29 | 30 | // ReleaseObject 将对象归还给对象池 31 | func (p *ObjectPool) ReleaseObject(object *Object) { 32 | p.objects <- object 33 | } 34 | -------------------------------------------------------------------------------- /creational/objectpool/objectpool_test.go: -------------------------------------------------------------------------------- 1 | package objectpool 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestObjectPool(t *testing.T) { 10 | assert := assert.New(t) 11 | 12 | pool := NewObjectPool(3) 13 | 14 | object1 := pool.AcquireObject() 15 | assert.Equal(0, object1.ID) 16 | 17 | object2 := pool.AcquireObject() 18 | assert.Equal(1, object2.ID) 19 | 20 | pool.ReleaseObject(object1) 21 | assert.Equal(0, object1.ID) 22 | 23 | object3 := pool.AcquireObject() 24 | assert.Equal(2, object3.ID) 25 | } 26 | -------------------------------------------------------------------------------- /creational/prototype/README.md: -------------------------------------------------------------------------------- 1 | ## 原型模式 2 | 3 | 原型模式(Prototype Pattern)将这个克隆的过程委派给了被克隆的实际对象,被克隆的对象就叫做“原型”。原型模式使对象能复制自身,并且暴露到接口中,使客户端面向接口编程时,不知道接口实际对象的情况下生成新的对象。原型模式配合原型管理器使用,使得客户端在不知道具体类的情况下,通过接口管理器得到新的实例,并且包含部分预设定配置。 4 | -------------------------------------------------------------------------------- /creational/prototype/prototype.go: -------------------------------------------------------------------------------- 1 | package prototype 2 | 3 | // Shape 接口定义了克隆方法 4 | type Shape interface { 5 | Clone() Shape 6 | GetType() string 7 | } 8 | 9 | // Circle 结构体表示圆形 10 | type Circle struct { 11 | Type string 12 | } 13 | 14 | func (c *Circle) Clone() Shape { 15 | return &Circle{Type: c.Type} 16 | } 17 | 18 | func (c *Circle) GetType() string { 19 | return c.Type 20 | } 21 | -------------------------------------------------------------------------------- /creational/prototype/prototype_test.go: -------------------------------------------------------------------------------- 1 | package prototype 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestCircleClone(t *testing.T) { 10 | assert := assert.New(t) 11 | 12 | circle := &Circle{Type: "Circle"} 13 | cloneCircle := circle.Clone() 14 | 15 | actual := cloneCircle.GetType() 16 | assert.Equal(circle.GetType(), actual) 17 | } 18 | -------------------------------------------------------------------------------- /creational/simplefactory/README.md: -------------------------------------------------------------------------------- 1 | ## 简单工厂模式 2 | 3 | 简单工厂模式(Simple Factory Pattern):定义一个工厂函数/方法,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。 4 | -------------------------------------------------------------------------------- /creational/simplefactory/simplefactory.go: -------------------------------------------------------------------------------- 1 | package simplefactory 2 | 3 | type ShapeType string 4 | 5 | const ( 6 | ShapeTypeCircle ShapeType = "circle" 7 | ShapeTypeRectangle ShapeType = "rectangle" 8 | ) 9 | 10 | // Shape 接口定义 11 | type Shape interface { 12 | Draw() string 13 | } 14 | 15 | // Circle 结构体 16 | type Circle struct{} 17 | 18 | func (c Circle) Draw() string { 19 | return "Drawing Circle" 20 | } 21 | 22 | // Rectangle 结构体 23 | type Rectangle struct{} 24 | 25 | func (r Rectangle) Draw() string { 26 | return "Drawing Rectangle" 27 | } 28 | 29 | // NewShape 根据 shapeType 创建具体的 Shap 实例. 30 | func NewShape(shapeType ShapeType) Shape { 31 | switch shapeType { 32 | case ShapeTypeCircle: 33 | return Circle{} 34 | case ShapeTypeRectangle: 35 | return Rectangle{} 36 | default: 37 | return nil 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /creational/simplefactory/simplefactory_test.go: -------------------------------------------------------------------------------- 1 | package simplefactory 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestCircle(t *testing.T) { 10 | assert := assert.New(t) 11 | 12 | circle := NewShape(ShapeTypeCircle) 13 | actual := circle.Draw() 14 | assert.Equal("Drawing Circle", actual) 15 | } 16 | 17 | func TestRectangle(t *testing.T) { 18 | assert := assert.New(t) 19 | 20 | rectangle := NewShape(ShapeTypeRectangle) 21 | actual := rectangle.Draw() 22 | assert.Equal("Drawing Rectangle", actual) 23 | } 24 | -------------------------------------------------------------------------------- /creational/singleton/README.md: -------------------------------------------------------------------------------- 1 | ## 单例模式 2 | 3 | 单例模式(Singleton Pattern),是最简单的一个模式。在 Go 中,单例模式指的是全局只有一个实例,并且它负责创建自己的对象。单例模式不仅有利于减少内存开支,还有减少系统性能开销、防止多个实例产生冲突等优点。 4 | -------------------------------------------------------------------------------- /creational/singleton/eager.go: -------------------------------------------------------------------------------- 1 | package singleton 2 | 3 | // 示例模式:单例模式 -> 饿汉方法. 4 | 5 | // 初始化一个全局的单例变量. 6 | var eager *Eager 7 | 8 | // 定义单例模式类型 9 | type Eager struct { 10 | count int 11 | } 12 | 13 | // Eager 类型 Inc 方法. 14 | func (e *Eager) Inc() { 15 | e.count++ 16 | } 17 | 18 | // 初始化单例实例,这里不建议用 init() 函数,因为使用 init 函数初始化时, 19 | // 开发者无感知,不利于维护,容易出篓子. 20 | func InitEager(count int) { 21 | eager = &Eager{count: count} 22 | } 23 | 24 | // 获取全局的单例实例,这里只读,是并发安全的. 25 | func GetEager() *Eager { 26 | return eager 27 | } 28 | -------------------------------------------------------------------------------- /creational/singleton/eager_test.go: -------------------------------------------------------------------------------- 1 | package singleton 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | // 初始化单例实例 11 | func TestMain(m *testing.M) { 12 | // 程序运行时初始化 13 | InitEager(3) 14 | os.Exit(m.Run()) 15 | } 16 | 17 | // 调用GetEager 函数获取单例实例 18 | func TestGetEager(t *testing.T) { 19 | assert := assert.New(t) 20 | 21 | eager := &Eager{count: 3} 22 | ins := GetEager() 23 | 24 | assert.Equal(ins, eager) 25 | } 26 | -------------------------------------------------------------------------------- /creational/singleton/lazy.go: -------------------------------------------------------------------------------- 1 | package singleton 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // 示例模式:单例模式 -> 懒汉方法. 9 | 10 | var ( 11 | // 初始化一个全局的单例变量. 12 | lazy *Lazy 13 | once sync.Once 14 | ) 15 | 16 | // 定义单例模式类型. 17 | type Lazy struct{} 18 | 19 | // 定义 Lazy 类型 SayHi 方法. 20 | func (lz *Lazy) SayHi() { 21 | fmt.Println("Hi!") 22 | } 23 | 24 | // 初始化并获取全局单例实例. 25 | // 这里需要加锁,防止多个协程同时获取实例时,造成的并发不安全 26 | // 懒汉方法在获取并初始化实例时,可能需要传入参数,例如 GetLazy(3),这样不是很优雅, 27 | // 所以在实际开发中,我更喜欢用饿汉方法. 28 | func GetLazy() *Lazy { 29 | once.Do(func() { 30 | lazy = &Lazy{} 31 | }) 32 | 33 | return lazy 34 | } 35 | -------------------------------------------------------------------------------- /creational/singleton/lazy_test.go: -------------------------------------------------------------------------------- 1 | package singleton 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | const lazyCount = 500 11 | 12 | // 调用GetLazy 函数获取单例实例 13 | func TestGetLazy(t *testing.T) { 14 | assert := assert.New(t) 15 | 16 | // 使用时初始化 17 | lazy2 := GetLazy() 18 | lazy3 := GetLazy() 19 | 20 | // 测试 GetLazy 返回的是同一个对象 21 | assert.Same(lazy2, lazy3) 22 | } 23 | 24 | // 获取500次,Lazy 是否总是同一个 Lazy 25 | func TestParallelGetLazy(t *testing.T) { 26 | assert := assert.New(t) 27 | 28 | wg := sync.WaitGroup{} 29 | wg.Add(lazyCount) 30 | lazies := [lazyCount]*Lazy{} 31 | for i := 0; i < lazyCount; i++ { 32 | go func(index int) { 33 | lazies[index] = GetLazy() 34 | wg.Done() 35 | }(i) 36 | } 37 | wg.Wait() 38 | 39 | for i := 1; i < lazyCount; i++ { 40 | assert.Same(lazies[i], lazies[i-1]) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/superproj/design-pattern 2 | 3 | go 1.22.2 4 | 5 | require github.com/stretchr/testify v1.9.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 6 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /images/abstract-factorys-method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onexstack/design-pattern/c46038272b957dacbbda59a0def3e0fe9e55ec8f/images/abstract-factorys-method.png -------------------------------------------------------------------------------- /images/breaker-state-machine-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onexstack/design-pattern/c46038272b957dacbbda59a0def3e0fe9e55ec8f/images/breaker-state-machine-flow.png -------------------------------------------------------------------------------- /images/breaker-state-machine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onexstack/design-pattern/c46038272b957dacbbda59a0def3e0fe9e55ec8f/images/breaker-state-machine.png -------------------------------------------------------------------------------- /images/composite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onexstack/design-pattern/c46038272b957dacbbda59a0def3e0fe9e55ec8f/images/composite.png -------------------------------------------------------------------------------- /images/pub-sub-pattern-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onexstack/design-pattern/c46038272b957dacbbda59a0def3e0fe9e55ec8f/images/pub-sub-pattern-0.png -------------------------------------------------------------------------------- /images/pub-sub-pattern-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onexstack/design-pattern/c46038272b957dacbbda59a0def3e0fe9e55ec8f/images/pub-sub-pattern-1.png -------------------------------------------------------------------------------- /images/three-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onexstack/design-pattern/c46038272b957dacbbda59a0def3e0fe9e55ec8f/images/three-code.png -------------------------------------------------------------------------------- /messaging/fanin/README.md: -------------------------------------------------------------------------------- 1 | ## 扇入模式 2 | 3 | 扇入模式(Fan-in Pattern,或者叫扇入模式/汇聚模式/漏入模式)是一种常见的设计模式,用于将多个输入通道中的数据合并到单个输出通道中。Fan-in 模式通常用于将多个并发执行的任务的结果组合到一个单一的数据流中,实现数据聚合的目的。该模式既可以提高并发性能,又可以简化代码结构,使数据处理更加灵活和高效。 4 | -------------------------------------------------------------------------------- /messaging/fanin/fan_in.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | // Merge 函数实现了 FanIn 操作,将不同的通道组合成一个 8 | func Merge(cs ...<-chan int) <-chan int { 9 | var wg sync.WaitGroup 10 | 11 | out := make(chan int, 3) 12 | 13 | wg.Add(len(cs)) 14 | 15 | // send 函数从输入通道 c 中复制值发送到 out,直到 c 关闭,然后调用 wg.Done 16 | send := func(c <-chan int) { 17 | for n := range c { 18 | out <- n 19 | } 20 | wg.Done() 21 | } 22 | 23 | // 启动多个 goroutine 开始工作 24 | for _, c := range cs { 25 | go send(c) 26 | } 27 | 28 | // 启动一个 goroutine,在所有 send goroutine 完成后关闭 out。必须在 wg.Add 调用之后开始 29 | go func() { 30 | wg.Wait() 31 | close(out) 32 | }() 33 | 34 | return out 35 | } 36 | 37 | // generateNumbersPipeline 函数生成一个通道,用于发送给定的整数切片中的数字 38 | func generateNumbersPipeline(numbers []int) <-chan int { 39 | out := make(chan int) 40 | go func() { 41 | for _, n := range numbers { 42 | out <- n 43 | } 44 | close(out) // 发送完成后关闭通道 45 | }() 46 | return out 47 | } 48 | 49 | // squareNumber 函数接收一个整数通道,并将每个收到的数字平方后发送到新通道中 50 | func squareNumber(in <-chan int) <-chan int { 51 | out := make(chan int) 52 | go func() { 53 | for n := range in { 54 | out <- n * n 55 | } 56 | close(out) // 发送完成后关闭通道 57 | }() 58 | return out 59 | } 60 | -------------------------------------------------------------------------------- /messaging/fanin/fan_in_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func ExampleFanIn() { 8 | // 第一路输入源 9 | dataStreams1 := []int{13, 44, 56, 99, 9, 45, 67, 90, 78, 23} 10 | // 生成带有输入的通道 11 | inputChan1 := generateNumbersPipeline(dataStreams1) 12 | 13 | // 第二路输入源 14 | dataStreams2 := []int{2, 4, 6, 9, 1, 1, 2, 3, 7, 8} 15 | inputChan2 := generateNumbersPipeline(dataStreams2) 16 | 17 | // 对每个输入通道进行平方操作 18 | c1 := squareNumber(inputChan1) 19 | c2 := squareNumber(inputChan2) 20 | 21 | // 将两路数据的平方数进行合并 22 | out := Merge(c1, c2) 23 | 24 | sum := 0 25 | 26 | // 计算合并后的平方数的总和 27 | for c := range out { 28 | sum += c 29 | } 30 | 31 | fmt.Printf("FanIn 合并后的平方数总和为: %d\n", sum) 32 | // Output: 33 | // FanIn 合并后的平方数总和为: 36615 34 | } 35 | -------------------------------------------------------------------------------- /messaging/fanout/README.md: -------------------------------------------------------------------------------- 1 | ## 扇出模式 2 | 3 | 扇出模式(Fan-Out)用于将单个输入通道中的数据分发到多个输出通道中。在并发编程中,Fan-out 模式通常用于将数据同时传递给多个处理任务,以提高吞吐量和并发性能。该模式能够有效地利用多核处理器和并发执行,使程序的处理速度更加高效。 4 | -------------------------------------------------------------------------------- /messaging/fanout/fan_out.go: -------------------------------------------------------------------------------- 1 | package fanout 2 | 3 | import "sync" 4 | 5 | // Split 将一个通道分发到多个通道,数据轮流分发 6 | func Split(ch <-chan int, n int) []chan int { 7 | cs := []chan int{} 8 | for i := 0; i < n; i++ { 9 | cs = append(cs, make(chan int)) 10 | } 11 | 12 | distributeToChannels := func(ch <-chan int, cs []chan int) { 13 | defer func() { 14 | for _, c := range cs { 15 | close(c) 16 | } 17 | }() 18 | 19 | for { 20 | select { 21 | case val, ok := <-ch: 22 | if !ok { 23 | return 24 | } 25 | for _, c := range cs { 26 | c <- val 27 | } 28 | } 29 | } 30 | } 31 | 32 | go distributeToChannels(ch, cs) 33 | 34 | return cs 35 | } 36 | 37 | // Split2 将一个通道分发到多个通道,每个 worker 分发一轮数据 38 | func Split2(ch <-chan int, n int) []chan int { 39 | cs := []chan int{} 40 | for i := 0; i < n; i++ { 41 | cs = append(cs, make(chan int)) 42 | } 43 | 44 | var wg sync.WaitGroup 45 | distributeToChannels := func(ch <-chan int, cs []chan int) { 46 | val, ok := <-ch 47 | if !ok { 48 | return 49 | } 50 | for _, c := range cs { 51 | c <- val 52 | } 53 | wg.Done() 54 | } 55 | 56 | for i := 0; i < n; i++ { 57 | wg.Add(1) 58 | go distributeToChannels(ch, cs) 59 | } 60 | 61 | go func() { 62 | wg.Wait() 63 | for _, c := range cs { 64 | close(c) 65 | } 66 | }() 67 | 68 | return cs 69 | } 70 | 71 | // Split3 将一个通道分发到多个通道,随机分发数据到不同通道 72 | func Split3(ch <-chan int, n int) []chan int { 73 | cs := make([]chan int, n) 74 | for i := 0; i < n; i++ { 75 | cs[i] = make(chan int) 76 | } 77 | 78 | distributeToChannels := func(ch <-chan int, cs []chan int) { 79 | defer func() { 80 | for _, c := range cs { 81 | close(c) 82 | } 83 | }() 84 | 85 | for { 86 | for _, c := range cs { 87 | select { 88 | case val, ok := <-ch: 89 | if !ok { 90 | return 91 | } 92 | c <- val 93 | } 94 | } 95 | } 96 | } 97 | 98 | go distributeToChannels(ch, cs) 99 | 100 | return cs 101 | } 102 | 103 | // gen 函���将一组整数转换为一个通道,按顺序发送整数并在发送完毕后关闭通道 104 | func gen(nums ...int) <-chan int { 105 | out := make(chan int) 106 | go func() { 107 | defer close(out) 108 | for _, n := range nums { 109 | out <- n 110 | } 111 | }() 112 | return out 113 | } 114 | 115 | // sq 函数接收一个整数通道,返回一个按平方处理过的整数通道,并在处理完毕后关闭通道 116 | func sq(in <-chan int) <-chan int { 117 | out := make(chan int) 118 | go func() { 119 | for n := range in { 120 | out <- n * n 121 | } 122 | close(out) 123 | }() 124 | return out 125 | } 126 | -------------------------------------------------------------------------------- /messaging/fanout/fan_out_complex.go: -------------------------------------------------------------------------------- 1 | package fanout 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | "sync/atomic" 7 | 8 | "go.uber.org/zap" //https://github.com/uber-go/zap 9 | //Blazing fast, structured, leveled logging in Go. 10 | ) 11 | 12 | var ( 13 | log, _ = zap.NewDevelopment() 14 | ) 15 | 16 | // Settings of pipeline 17 | const ( 18 | MaxWorkers = 16 19 | MaxQueueSize = 512 20 | MasterQueueSize = MaxQueueSize * MaxWorkers 21 | ) 22 | 23 | // IDispatcher Message 24 | type IDispatcher interface { 25 | Before(context.Context) error 26 | After() error 27 | Process(interface{}) error 28 | } 29 | 30 | // worker each work will dispatch message to several channels 31 | type worker struct { 32 | index uint32 33 | mutex *sync.Mutex 34 | running bool 35 | chain chan interface{} 36 | debug bool 37 | idle uint32 38 | dispatcher IDispatcher //hold a dispacher,需要自己实现一个dispatcher 工厂 39 | } 40 | 41 | // Pipeline of workers 42 | type Pipeline struct { 43 | workers map[int]*worker 44 | chain chan interface{} 45 | } 46 | 47 | // DispatcherBuilder create Dispatcher 48 | type DispatcherBuilder func() IDispatcher 49 | 50 | // Start run 51 | func (p *Pipeline) Start(ctx context.Context) { 52 | go func(pipe *Pipeline) { 53 | for { 54 | expectationWorkers := len(pipe.chain) % MaxWorkers 55 | if expectationWorkers >= MaxWorkers { 56 | expectationWorkers = 0 57 | } 58 | select { 59 | case <-ctx.Done(): 60 | return 61 | case val, ok := <-pipe.chain: 62 | if !ok { 63 | return 64 | } 65 | go pipe.workers[expectationWorkers].stream(val) 66 | } 67 | } 68 | }(p) 69 | } 70 | 71 | // Dispatch message to chains 72 | func (p *Pipeline) Dispatch(msg interface{}) { 73 | p.chain <- msg 74 | } 75 | 76 | // NewPipeline create a Workflow with a dispacher builder and some workers 77 | func NewPipeline(d DispatcherBuilder, idle uint32, debug bool) *Pipeline { 78 | 79 | ch := make(chan interface{}, MasterQueueSize) 80 | 81 | wk := make(map[int]*worker) 82 | for i := 0; i < MaxWorkers; i++ { 83 | wk[i] = &worker{ 84 | index: uint32(i + 1), 85 | chain: make(chan interface{}, MaxQueueSize), 86 | mutex: new(sync.Mutex), 87 | debug: debug, 88 | idle: idle, 89 | dispatcher: d(), //build real dispatcher 90 | } 91 | } 92 | return &Pipeline{workers: wk, chain: ch} 93 | } 94 | 95 | func (c *worker) stream(val interface{}) { 96 | c.chain <- val 97 | if !c.running { 98 | c.mutex.Lock() 99 | c.running = true 100 | ctx, cancel := context.WithCancel(context.Background()) 101 | defer func(w *worker, cancel context.CancelFunc) { 102 | if w.debug { 103 | log.Info("Worker leaving", zap.Any("index", w.index), zap.Any("idle", w.idle)) 104 | } 105 | 106 | if c.dispatcher != nil { 107 | err := c.dispatcher.After() 108 | if err != nil { 109 | log.Error("can not finish track issue", zap.Error(err)) 110 | } 111 | } 112 | 113 | cancel() 114 | w.mutex.Unlock() 115 | w.running = false 116 | }(c, cancel) 117 | 118 | if c.dispatcher != nil { 119 | err := c.dispatcher.Before(ctx) 120 | if err != nil { 121 | log.Error("can not start worker", zap.Error(err)) 122 | } 123 | } 124 | 125 | var idle uint32 = 0 126 | for { 127 | select { 128 | case msg := <-c.chain: 129 | atomic.StoreUint32(&idle, 0) 130 | if msg != nil && c.dispatcher != nil { 131 | err := c.dispatcher.Process(msg) 132 | if err != nil { 133 | log.Error("can not process message", zap.Any("msg", &msg), zap.Error(err)) 134 | } 135 | } 136 | default: 137 | atomic.AddUint32(&idle, 1) 138 | if i := atomic.LoadUint32(&idle); i > 0 { 139 | if i > c.idle { 140 | return 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /messaging/fanout/fan_out_complex_test.go: -------------------------------------------------------------------------------- 1 | package fanout 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "testing" 7 | "time" 8 | 9 | "google.golang.org/grpc" 10 | ) 11 | 12 | // taggingDispatcher implement our dispatcher interface 13 | type taggingDispatcher struct { 14 | Address string 15 | // stream proto.StreamClient 16 | conn *grpc.ClientConn 17 | } 18 | type messageContent struct { 19 | content string 20 | priority int 21 | } 22 | 23 | func TestComplexStreamingFanOut(t *testing.T) { 24 | 25 | builder := func() IDispatcher { 26 | return &taggingDispatcher{Address: "127.0.0.2"} 27 | } 28 | tagging := &Tagging{ 29 | topic: "new topic", 30 | pipeline: NewPipeline(builder, 2, true), 31 | } 32 | 33 | tagging.pipeline.Dispatch(messageContent{"all,please stay home", 1000}) 34 | 35 | tagging.pipeline.Start(context.Background()) 36 | 37 | //模拟处理过程,让工作者线程完成工作 38 | time.Sleep(time.Second * 2) 39 | t.Log("Done") 40 | } 41 | 42 | type Tagging struct { 43 | topic string 44 | pipeline *Pipeline 45 | } 46 | 47 | func (d *taggingDispatcher) Before(ctx context.Context) error { 48 | 49 | fmt.Println("i'm doing somthing before processing") 50 | 51 | conn, err := grpc.Dial(d.Address, grpc.WithInsecure()) 52 | if err != nil { 53 | return err 54 | } 55 | d.conn = conn 56 | // // // client := proto.NewClient(conn) 57 | // // stream, err := client.StreamMetric(ctx) 58 | // // if err != nil { 59 | // // return err 60 | // // } 61 | // // d.stream = stream 62 | 63 | return nil 64 | } 65 | 66 | func (d *taggingDispatcher) After() error { 67 | // _, err := d.stream.CloseAndRecv() 68 | // e := d.conn.Close() 69 | // if e != nil { 70 | // log.Error("close connection error", field.Error(e)) 71 | // } 72 | //return err 73 | fmt.Println("i'm doing somthing After processing") 74 | return nil 75 | } 76 | 77 | func (d *taggingDispatcher) Process(msg interface{}) error { 78 | 79 | content := msg.(messageContent) 80 | fmt.Println("i'm doing processing,with conten", content) 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /messaging/fanout/fan_out_test.go: -------------------------------------------------------------------------------- 1 | package fanout 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | // 多工作者,重复分发 10 | func TestFanOutDuplicateMultiWorkers(t *testing.T) { 11 | 12 | //一路输入源 13 | dataStreams := []int{13, 44, 56, 99, 9, 45, 67, 90, 78, 23} 14 | //generator integer stream 15 | inputChan := gen(dataStreams...) 16 | 17 | // transfer to 18 | ch := sq(inputChan) 19 | 20 | // split it to 3 channel 21 | // 重复分发 22 | outArray := Split2(ch, 3) 23 | 24 | length := len(outArray) 25 | t.Log("length of out channel:", length) 26 | var wg sync.WaitGroup 27 | wg.Add(length) 28 | for i := 0; i < length; i++ { 29 | 30 | go func(in <-chan int, index int) { 31 | sum := 0 32 | for item := range in { 33 | sum += item 34 | } 35 | fmt.Println("worker:", index, sum) 36 | 37 | wg.Done() 38 | }(outArray[i], i) 39 | } 40 | wg.Wait() 41 | } 42 | 43 | // 单个工作者,重复分发 44 | func TestFanOutDuplicate(t *testing.T) { 45 | 46 | //一路输入源 47 | dataStreams := []int{13, 44, 56, 99, 9, 45, 67, 90, 78, 23} 48 | //generator integer stream 49 | inputChan := gen(dataStreams...) 50 | 51 | // transfer to 52 | ch := sq(inputChan) 53 | 54 | // split it to 3 channel 55 | // 重复分发 56 | outArray := Split(ch, 3) 57 | 58 | length := len(outArray) 59 | t.Log("length of out channel:", length) 60 | var wg sync.WaitGroup 61 | wg.Add(length) 62 | for i := 0; i < length; i++ { 63 | 64 | go func(in <-chan int, index int) { 65 | sum := 0 66 | for item := range in { 67 | sum += item 68 | } 69 | fmt.Println("worker:", index, sum) 70 | 71 | wg.Done() 72 | }(outArray[i], i) 73 | } 74 | wg.Wait() 75 | } 76 | 77 | // 随机分发 78 | // worker: 2 11245 79 | // worker: 0 14988 80 | // worker: 1 10117 81 | func TestFanOutRandom(t *testing.T) { 82 | 83 | //一路输入源 84 | dataStreams := []int{13, 44, 56, 99, 9, 45, 67, 90, 78, 23} 85 | //generator integer stream 86 | inputChan := gen(dataStreams...) 87 | 88 | // transfer to 89 | ch := sq(inputChan) 90 | 91 | // split it to 3 channel 92 | // 重复分发 93 | outArray := Split3(ch, 3) 94 | 95 | length := len(outArray) 96 | t.Log("length of out channel:", length) 97 | var wg sync.WaitGroup 98 | wg.Add(length) 99 | for i := 0; i < length; i++ { 100 | 101 | go func(in <-chan int, index int) { 102 | sum := 0 103 | for item := range in { 104 | sum += item 105 | } 106 | fmt.Println("worker:", index, sum) 107 | 108 | wg.Done() 109 | }(outArray[i], i) 110 | } 111 | wg.Wait() 112 | } 113 | 114 | func TestManualFanOutNumbersSeq(T *testing.T) { 115 | 116 | //一路输入源 117 | dataStreams := []int{13, 44, 56, 99, 9, 45, 67, 90, 78, 23} 118 | // generate the common channel with inputs 119 | inputChan1 := gen(dataStreams...) 120 | inputChan2 := gen(dataStreams...) 121 | 122 | //Manual Fan-out to 2 Go-routine 123 | c1 := sq(inputChan1) 124 | c2 := sq(inputChan2) 125 | 126 | fmt.Print("c1 queue: ") 127 | for n := range c1 { 128 | fmt.Print(n, " ") 129 | } 130 | fmt.Println() 131 | 132 | fmt.Print("c2 queue: ") 133 | for n := range c2 { 134 | fmt.Print(n, " ") 135 | } 136 | fmt.Println() 137 | 138 | } 139 | -------------------------------------------------------------------------------- /messaging/futurespromises/README.md: -------------------------------------------------------------------------------- 1 | ## 未来与承诺模式 2 | 3 | 未来与承诺模式(Futures & Promises Pattern)用于异步处理任务和数据。在这种模式下,Future 表示一个未完成的操作或值,而 Promise 则表示接收该操作结果的凭证。 4 | -------------------------------------------------------------------------------- /messaging/futurespromises/futurespromises.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func asyncOperation() <-chan int { 9 | result := make(chan int) 10 | 11 | go func() { 12 | time.Sleep(2 * time.Second) 13 | result <- 42 14 | }() 15 | 16 | return result 17 | } 18 | 19 | func main() { 20 | future := asyncOperation() 21 | 22 | fmt.Println("Performing other operations...") 23 | 24 | value := <-future 25 | fmt.Println("Async operation result:", value) 26 | } 27 | -------------------------------------------------------------------------------- /messaging/pubsub/README.md: -------------------------------------------------------------------------------- 1 | ## 发布订阅模式 2 | 3 | 发布订阅模式(Publish-Subscribe Pattern)用于实现多个发布者(Publishers)将消息发送给多个订阅者(Subscribers)的系统。在该模式中,发布者和订阅者之间是解耦的,发布者不直接发送消息给订阅者,而是通过消息通道(Channel)或者中介者(Mediator)来进行消息的传递。这种方式使得系统更加灵活,可以动态地增加或移除发布者和订阅者,同时减少了组件之间的依赖关系。 4 | -------------------------------------------------------------------------------- /messaging/pubsub/example/README.md: -------------------------------------------------------------------------------- 1 | # 发布订阅模式 2 | 3 | 发布-订阅是一种消息传递模式,基本设计原则是将消息发布者和提供者分开,常常用于在不同组件之间传递消息。 4 | 5 | ![图示关系](../../images/pub-sub-pattern-0.png) 6 | 发布订阅模式往往实现为<消息代理,消息中间件,消息队列>等 7 | 8 | 该模式中的三个关键类型:消息本身、消息主题、订阅用户。 9 | ![图示关系](../../images/pub-sub-pattern-1.png) 10 | 11 | 图片来源:[pubsub-pattern.md](https://github.com/imsardine/dev-notes/blob/source/docs/pubsub-pattern.md) 12 | 13 | 现实生活中的各种信息平台,就是很好的发布订阅的例子,比如某八戒、某无忧等。 14 | 15 | 在发布订阅模型中,每条消息都会传送给多个订阅者。发布者通常不会知道、也不关心哪一个订阅者正在接收主题消息。订阅者和发布者可以在运行时动态添加是一种松散的耦合关系,这使得系统的复杂性可以随时间的推移而增长。在现实生活中,不同城市的象天气预报也是这个模式。 16 | 17 | 这里演示,一个拼车例子,车主发布拼车(Topic)消息,消息推送到订阅拼车(Topic)信息的所有用户. 18 | 19 | 并模拟以下情形: 20 | 21 | + 车主(Topic)发布拼车消息 22 | + 拼车用户订阅拼车消息(Topic) 23 | + 拼车用户处理收到的拼车消息 24 | -------------------------------------------------------------------------------- /messaging/pubsub/example/message.go: -------------------------------------------------------------------------------- 1 | package messaging 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "time" 8 | ) 9 | 10 | // Message for msg in Message bus 11 | type Message struct { 12 | Seq int 13 | Text string 14 | From Session //消息来源 15 | } 16 | 17 | // User for user 18 | type User struct { 19 | ID uint64 20 | Name string 21 | } 22 | 23 | // Session inherit user 24 | type Session struct { 25 | User 26 | Timestamp time.Time 27 | } 28 | 29 | // Subscription for user 30 | // Subscription is a session 31 | type Subscription struct { 32 | Session 33 | topicName string 34 | ctx context.Context 35 | cancel context.CancelFunc 36 | Ch chan<- Message //发送队列 37 | Inbox chan Message //接收消息的队列 38 | } 39 | 40 | func newSubscription(uid uint64, topicName string, UserQueueSize int) Subscription { 41 | 42 | ctx, cancel := context.WithCancel(context.Background()) 43 | 44 | return Subscription{ 45 | Session: Session{User{ID: uid}, time.Now()}, 46 | ctx: ctx, 47 | cancel: cancel, 48 | Ch: make(chan<- Message, UserQueueSize), //用于跟单个用户通信的消息队列,用户发送消息 49 | Inbox: make(chan Message, UserQueueSize), //用于跟单个用户通信的消息队列,用户接收消息 50 | } 51 | 52 | } 53 | 54 | // Cancel Message 55 | func (s *Subscription) Cancel() { 56 | s.cancel() 57 | } 58 | 59 | // Publish 这个表示用户订阅到感兴趣的主题的时候,同时也可以发送消息, 60 | // Publish 但是,示例中不演示这个用途 61 | // Publish 只有当channel无数据,且channel被close了,才会返回ok=false 62 | // Publish a message to subscription queue 63 | func (s *Subscription) Publish(msg Message) error { 64 | 65 | select { 66 | case <-s.ctx.Done(): 67 | return errors.New("Topic has been closed") 68 | default: 69 | s.Ch <- msg 70 | } 71 | return nil 72 | } 73 | 74 | // Receive message 75 | func (s *Subscription) Receive(out *Message) error { 76 | 77 | select { 78 | case <-s.ctx.Done(): 79 | return errors.New("Topic has been closed") 80 | case <-time.After(time.Millisecond * 100): 81 | return errors.New("time out error") 82 | case *out = <-s.Inbox: 83 | return nil 84 | } 85 | } 86 | 87 | // Topic that user is interested in 88 | // Topic should locate in MQ 89 | type Topic struct { 90 | UserQueueSize int 91 | Name string 92 | Subscribers map[uint64]Subscription //user list 93 | MessageHistory []Message //当前主题的消息历史,实际项目中可能需要限定大小并设置过期时间 94 | } 95 | 96 | // Publish 只有当channel无数据,且channel被close了,才会返回ok=false 97 | // Publish a message to subscription queue 98 | func (t *Topic) Publish(msg Message) error { 99 | 100 | //将消息发布给当前Topic的所有人 101 | for usersID, subscription := range t.Subscribers { 102 | if subscription.ID == usersID { 103 | subscription.Inbox <- msg 104 | } 105 | } 106 | //save message history 107 | t.MessageHistory = append(t.MessageHistory, msg) 108 | 109 | fmt.Println("current histroy message count: ", len(t.MessageHistory)) 110 | 111 | return nil 112 | } 113 | 114 | func (t *Topic) findUserSubscription(uid uint64, topicName string) (Subscription, bool) { 115 | // Get session or create one if it's the first 116 | 117 | if topicName != t.Name || t.Subscribers == nil || len(t.Subscribers) == 0 { 118 | return Subscription{}, false 119 | } 120 | if subscription, found := t.Subscribers[uid]; found { 121 | return subscription, true 122 | } 123 | return Subscription{}, false 124 | } 125 | 126 | // Subscribe a spec topic 127 | func (t *Topic) Subscribe(uid uint64, topicName string) (Subscription, bool) { 128 | 129 | if t.Name != topicName { 130 | return Subscription{}, false 131 | } 132 | 133 | // Get session or create one if it's the first 134 | if _, found := t.findUserSubscription(uid, topicName); !found { 135 | if t.Subscribers == nil { 136 | t.Subscribers = make(map[uint64]Subscription) 137 | } 138 | t.Subscribers[uid] = newSubscription(uid, topicName, t.UserQueueSize) 139 | } 140 | 141 | return t.Subscribers[uid], true 142 | } 143 | 144 | // Unsubscribe remove Subscription 145 | func (t *Topic) Unsubscribe(s Subscription) error { 146 | if _, found := t.findUserSubscription(s.ID, s.topicName); found { 147 | delete(t.Subscribers, s.ID) 148 | } 149 | return nil 150 | } 151 | 152 | // Delete topic 153 | func (t *Topic) Delete() error { 154 | t.Subscribers = nil 155 | t.Name = "" 156 | t.MessageHistory = nil 157 | return nil 158 | } 159 | -------------------------------------------------------------------------------- /messaging/pubsub/example/message_queue.go: -------------------------------------------------------------------------------- 1 | package messaging 2 | 3 | // Queue hold all topics 4 | type Queue struct { 5 | Topics map[string]Topic //topic ID<-----> topic Object 6 | } 7 | 8 | // AddTopic to Queue 9 | func (q *Queue) AddTopic(topicName string, topicUserQueueSize int) Topic { 10 | if q.Topics == nil { 11 | q.Topics = make(map[string]Topic) 12 | } 13 | if _, found := q.Topics[topicName]; !found { 14 | q.Topics[topicName] = Topic{UserQueueSize: topicUserQueueSize, Name: topicName} 15 | } 16 | return q.Topics[topicName] 17 | } 18 | -------------------------------------------------------------------------------- /messaging/pubsub/example/message_test.go: -------------------------------------------------------------------------------- 1 | package messaging 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "sync" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | //////////////////////////////// 12 | //通常意义上是,连接消息队列之后就可以发送消息 13 | //当订阅著之后才会收到相关Topic消息的推送 14 | //当前,省略连接队列的步骤和操作代码 15 | //////////////////////////////// 16 | 17 | func TestMessageSubAndPubWithTopic(t *testing.T) { 18 | var wg sync.WaitGroup 19 | 20 | topicName := "seeking passengers" 21 | //假设消息队列已经收到数据,加下来由topic处理 22 | topic := Topic{ 23 | Name: topicName, 24 | UserQueueSize: 5, 25 | } 26 | 27 | ctx, cancel := context.WithCancel(context.Background()) 28 | 29 | wg.Add(1) 30 | 31 | //user 1 32 | //用户tom订阅拼车消息,订阅的是车主发布的拼车消息 33 | if subScriberTom, ok := topic.Subscribe(123, topicName); ok { 34 | 35 | go func() { 36 | defer wg.Done() 37 | EXIT: 38 | for { 39 | select { 40 | case <-ctx.Done(): 41 | fmt.Println("tom receive cancel, exit") 42 | break EXIT 43 | default: 44 | msg := Message{} 45 | err := subScriberTom.Receive(&msg) 46 | if err == nil { 47 | fmt.Println("tom receive subscribed msg:", msg) 48 | } 49 | } 50 | time.Sleep(200) 51 | } 52 | }() 53 | } 54 | 55 | wg.Add(1) 56 | 57 | //订阅成功了 58 | //发送一个消息 59 | 60 | //用户Lily订阅拼车消息,订阅的是车主发布的拼车消息 61 | if subSCriptionLily, ok := topic.Subscribe(456, topicName); ok { 62 | go func() { 63 | defer wg.Done() 64 | EXIT: 65 | for { 66 | select { 67 | case <-ctx.Done(): 68 | fmt.Println("lily receive cancel, exit") 69 | break EXIT 70 | default: 71 | msg := Message{} 72 | err := subSCriptionLily.Receive(&msg) 73 | if err == nil { 74 | fmt.Println("lily receive subscribed msg:", msg) 75 | } 76 | } 77 | time.Sleep(200) 78 | } 79 | }() 80 | } 81 | 82 | go func() { 83 | //模拟发送消息 84 | msg := Message{ 85 | Text: "i am looking for 1 passenger", 86 | From: Session{User{123, "lily"}, time.Now()}, 87 | } 88 | topic.Publish(msg) 89 | 90 | msg = Message{ 91 | Text: "i am looking for 2 passenger", 92 | From: Session{User{123, "lucy"}, time.Now()}, 93 | } 94 | 95 | topic.Publish(msg) 96 | 97 | msg = Message{ 98 | Text: "i am looking for passenger as many as i can", 99 | From: Session{User{123, "rose"}, time.Now()}, 100 | } 101 | 102 | topic.Publish(msg) 103 | time.Sleep(time.Second) 104 | cancel() 105 | 106 | }() 107 | 108 | wg.Wait() 109 | fmt.Println("all message done,exit it") 110 | 111 | } 112 | -------------------------------------------------------------------------------- /messaging/pubsub/example/message_weather.go: -------------------------------------------------------------------------------- 1 | package messaging 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | type ( 9 | subscriber chan interface{} // 订阅者为一个管道 10 | topicFunc func(v interface{}) bool // 主题为一个过滤器 11 | ) 12 | 13 | // Publisher 发布者对象 14 | type Publisher struct { 15 | m sync.RWMutex // 读写锁 16 | buffer int // 订阅队列的缓存大小 17 | timeout time.Duration // 发布超时时间 18 | subscribers map[subscriber]topicFunc // 订阅者信息 19 | } 20 | 21 | // NewPublisher 构建一个发布者对象, 可以设置发布超时时间和缓存队列的长度 22 | func NewPublisher(publishTimeout time.Duration, buffer int) *Publisher { 23 | return &Publisher{ 24 | buffer: buffer, 25 | timeout: publishTimeout, 26 | subscribers: make(map[subscriber]topicFunc), 27 | } 28 | } 29 | 30 | // Subscribe 添加一个新的订阅者,订阅全部主题 31 | func (p *Publisher) Subscribe() chan interface{} { 32 | return p.SubscribeTopic(nil) 33 | } 34 | 35 | // SubscribeTopic 添加一个新的订阅者,订阅过滤器筛选后的主题 36 | func (p *Publisher) SubscribeTopic(topic topicFunc) chan interface{} { 37 | ch := make(chan interface{}, p.buffer) 38 | p.m.Lock() 39 | p.subscribers[ch] = topic 40 | p.m.Unlock() 41 | return ch 42 | } 43 | 44 | // Evict 退出订阅 45 | func (p *Publisher) Evict(sub chan interface{}) { 46 | p.m.Lock() 47 | defer p.m.Unlock() 48 | delete(p.subscribers, sub) 49 | close(sub) 50 | } 51 | 52 | // Publish 发布一个主题 53 | func (p *Publisher) Publish(v interface{}) { 54 | p.m.RLock() 55 | defer p.m.RUnlock() 56 | var wg sync.WaitGroup 57 | for sub, topic := range p.subscribers { 58 | wg.Add(1) 59 | go p.sendTopic(sub, topic, v, &wg) 60 | } 61 | wg.Wait() 62 | } 63 | 64 | // Close 关闭发布者对象,同时关闭所有的订阅者管道。 65 | func (p *Publisher) Close() { 66 | p.m.Lock() 67 | defer p.m.Unlock() 68 | for sub := range p.subscribers { 69 | delete(p.subscribers, sub) 70 | close(sub) 71 | } 72 | } 73 | 74 | // sendTopic 发送主题,可以容忍一定的超时 75 | func (p *Publisher) sendTopic(sub subscriber, topic topicFunc, v interface{}, wg *sync.WaitGroup) { 76 | defer wg.Done() 77 | if topic != nil && !topic(v) { 78 | return 79 | } 80 | select { 81 | case sub <- v: 82 | case <-time.After(p.timeout): 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /messaging/pubsub/example/message_weather_test.go: -------------------------------------------------------------------------------- 1 | package messaging 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | /*不同城市的象天气预报可以应用这个模式。*/ 11 | //这个是一个第三方的例子 12 | func TestMessageSubPub(t *testing.T) { 13 | p := NewPublisher(100*time.Millisecond, 10) 14 | defer p.Close() 15 | 16 | //订阅全部 17 | all := p.SubscribeTopic(nil) 18 | 19 | //订阅包含天气的消息 20 | onlyweathers := p.SubscribeTopic(func(v interface{}) bool { 21 | if s, ok := v.(string); ok { 22 | return strings.Contains(s, "weather") 23 | } 24 | return false 25 | }) 26 | 27 | p.Publish("weather bad, SH") 28 | p.Publish("weather fine,SZ") 29 | 30 | go func() { 31 | for msg := range all { 32 | fmt.Println("all:", msg) 33 | } 34 | }() 35 | 36 | go func() { 37 | for msg := range onlyweathers { 38 | fmt.Println("Received:", msg) 39 | } 40 | }() 41 | // 运行一定时间后退出 42 | time.Sleep(3 * time.Second) 43 | } 44 | -------------------------------------------------------------------------------- /messaging/pubsub/pubsub.go: -------------------------------------------------------------------------------- 1 | package pubsub 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Publisher 结构体表示发布者,包含订阅者的映射 8 | type Publisher struct { 9 | subscribers map[string]chan string 10 | } 11 | 12 | // NewPublisher 创建一个新的发布者实例 13 | func NewPublisher() *Publisher { 14 | return &Publisher{ 15 | subscribers: make(map[string]chan string), 16 | } 17 | } 18 | 19 | // Subscribe 订阅指定主题的消息 20 | func (p *Publisher) Subscribe(topic string, ch chan string) { 21 | p.subscribers[topic] = ch 22 | } 23 | 24 | // Unsubscribe 取消订阅指定主题的消息 25 | func (p *Publisher) Unsubscribe(topic string) { 26 | delete(p.subscribers, topic) 27 | } 28 | 29 | // Publish 发布消息到指定主题 30 | func (p *Publisher) Publish(topic, message string) { 31 | if ch, ok := p.subscribers[topic]; ok { 32 | ch <- message 33 | } 34 | } 35 | 36 | func main() { 37 | publisher := NewPublisher() 38 | 39 | ch1 := make(chan string) 40 | ch2 := make(chan string) 41 | 42 | publisher.Subscribe("topic1", ch1) 43 | publisher.Subscribe("topic2", ch2) 44 | 45 | // 启动订阅者的 goroutine 接收消息 46 | go func() { 47 | for { 48 | select { 49 | case msg := <-ch1: 50 | fmt.Println("Subscriber 1 received message:", msg) 51 | case msg := <-ch2: 52 | fmt.Println("Subscriber 2 received message:", msg) 53 | } 54 | } 55 | }() 56 | 57 | // 发布消息到指定主题 58 | publisher.Publish("topic1", "Hello, World!") 59 | publisher.Publish("topic2", "Greetings from Publisher!") 60 | } 61 | -------------------------------------------------------------------------------- /messaging/pubsub/pubsub_test.go: -------------------------------------------------------------------------------- 1 | package pubsub 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestPublishSubscribe(t *testing.T) { 9 | // 创建一个新的发布者实例 10 | publisher := NewPublisher() 11 | 12 | // 创建两个消息通道 13 | ch1 := make(chan string) 14 | ch2 := make(chan string) 15 | 16 | // 订阅两个不同的主题,并将消息通道传入 17 | publisher.Subscribe("topic1", ch1) 18 | publisher.Subscribe("topic2", ch2) 19 | 20 | // 启动一个 goroutine 来接收订阅的消息 21 | go func() { 22 | for { 23 | select { 24 | case msg := <-ch1: 25 | fmt.Println("Subscriber 1 received message:", msg) 26 | case msg := <-ch2: 27 | fmt.Println("Subscriber 2 received message:", msg) 28 | } 29 | } 30 | }() 31 | 32 | // 发布两条消息到不同的主题 33 | publisher.Publish("topic1", "Hello, World!") 34 | publisher.Publish("topic2", "Greetings from Publisher!") 35 | } 36 | -------------------------------------------------------------------------------- /messaging/pushpull/README.md: -------------------------------------------------------------------------------- 1 | # 推模式与拉模式 2 | 3 | 推模式与拉模式(Push & Pull Pattern)用于描述数据传递的方式。在 Push 模式下,数据的发布者直接推送数据给订阅者,而在 Pull 模式下,订阅者主动从数据源中拉取数据。 4 | -------------------------------------------------------------------------------- /messaging/pushpull/pushpull.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // Push 模式示例 9 | func pushData(dataCh chan<- int) { 10 | for i := 0; i < 5; i++ { 11 | dataCh <- i 12 | time.Sleep(time.Second) 13 | } 14 | close(dataCh) 15 | } 16 | 17 | // Pull 模式示例 18 | func pullData(dataCh <-chan int) { 19 | for data := range dataCh { 20 | fmt.Println("Pulled data:", data) 21 | } 22 | } 23 | 24 | func main() { 25 | pushCh := make(chan int) 26 | pullCh := make(chan int) 27 | 28 | go pushData(pushCh) 29 | go pullData(pullCh) 30 | 31 | for i := 0; i < 5; i++ { 32 | value := <-pushCh 33 | pullCh <- value 34 | } 35 | 36 | time.Sleep(5 * time.Second) 37 | } 38 | -------------------------------------------------------------------------------- /oneintro.md: -------------------------------------------------------------------------------- 1 | ## 创建型模式 2 | 建造者模式(Builder Pattern): 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示 3 | 工厂方法模式(Factory Method): 使一个类的实例化延迟到其子类, 定义一个用于创建对象的接口, 让子类决定将哪一个类实例化 4 | 对象池模式(Object Pool): 根据需求将预测的对象保存到channel中, 用于对象的生成成本大于维持成本 5 | 单例模式(singleton): 单例模式是最简单的设计模式之一, 保证一个类仅有一个实例, 并提供一个全局的访问接口 6 | 生成器模式(Generator): 生成器模式可以允许使用者在生成要使用的下一个值时与生成器并行运行 7 | 抽象工厂模式(Abstract Factory): 提供一个创建一系列相关或相互依赖对象的接口, 而无需指定它们具体的类 8 | 原型模式(Prototype Pattern): 复制一个已存在的实例 9 | 10 | ## 结构型模式 11 | 12 | 装饰模式(Decorator Pattern): 装饰模式使用对象组合的方式动态改变或增加对象行为, 在原对象的基础上增加功能 13 | 代理模式(Proxy Pattern): 代理模式用于延迟处理操作或者在进行实际操作前后对真实对象进行其它处理。 14 | 适配器模式(Adapter Pattern): 将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 15 | 组合模式(Composite): 组合模式有助于表达数据结构, 将对象组合成树形结构以表示"部分-整体"的层次结构, 常用于树状的结构 16 | 享元模式(Flyweight Pattern): 把多个实例对象共同需要的数据,独立出一个享元,从而减少对象数量和节省内存 17 | 外观模式(Facade Pattern): 外观模式在客户端和现有系统之间加入一个外观对象, 为子系统提供一个统一的接入接口, 类似与委托 18 | 桥接模式(Bridge Pattern): 桥接模式分离抽象部分和实现部分,使得两部分可以独立扩展 19 | 20 | ## 行为型模式 21 | 22 | 观察者模式(Observer): 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新 23 | 策略模式(Strategy): 定义一系列算法,让这些算法在运行时可以互换,使得分离算法,符合开闭原则 24 | 状态模式(State Pattern): 用于系统中复杂对象的状态转换以及不同状态下行为的封装问题 25 | 访问者模式(Visitor Pattern): 访问者模式是将对象的数据和操作分离 26 | 模板方法模式(Template Method Pattern): 模版方法使用匿名组合的继承机制, 将通用的方法和属性放在父类中, 具体的实现放在子类中延迟执行 27 | 备忘录模式(Memento Pattern): 备忘录模式捕获一个对象的内部状态,并在对象之外保存这个状态 28 | 中介模式(Mediator Pattern): 中介者模式用一个中介对象来封装一系列对象交互,将多对多关联转换成一对多,构成星状结构 29 | 迭代器模式(Iterator Pattern): 可以配合访问者模式,将不同的数据结构,使用迭代器遍历 30 | 解释器模式(Interpreter Pattern): 解释器模式实现一个表达式接口,该接口解释一个特定的上下文。通常用于SQL解析和符号处理引擎 31 | 命令模式(Command Pattern): 命令模式是一种数据驱动模式,将请求封装成一个对象,从而可以用不同的请求对客户进行参数化,实现调用者和接收者的解藕 32 | 责任链模式(Chain of Responsibility): 责任链模式是将处理请求的多个对象连成一条链(类似队列),每个对象都包含下一个对象的引用,请求沿着链传递,直到被处理 33 | 34 | ## 同步模式 35 | 信号量模式(Semaphore): 信号量是一种同步模式,对有限数量的资源同步互斥 36 | 发布订阅模式(publish-subscribe): 有别于传统的生产者消费者,pubsub模型将消费发布给一个主题 37 | -------------------------------------------------------------------------------- /profiling/timing/README.md: -------------------------------------------------------------------------------- 1 | ## 计时函数模式 2 | 3 | 计时函数模式(Timing Functions Pattern)用于测量和监控程序或函数执行时间的模式。通过计时函数,可以精确地测量代码段的执行时间,帮助优化程序性能和识别潜在的瓶颈。 4 | -------------------------------------------------------------------------------- /profiling/timing/timing.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func task() { 9 | start := time.Now() 10 | defer func() { 11 | elapsed := time.Since(start) 12 | fmt.Printf("Task completed in %s\n", elapsed) 13 | }() 14 | 15 | // 模拟任务执行 16 | sum := 0 17 | for i := 1; i <= 1000000; i++ { 18 | sum += i 19 | } 20 | } 21 | 22 | func main() { 23 | fmt.Println("Timing Functions Example") 24 | task() 25 | } 26 | -------------------------------------------------------------------------------- /stability/bulkhead/README.md: -------------------------------------------------------------------------------- 1 | ## 隔离模式 2 | 3 | 隔离模式(Bulkheads Pattern)用于隔离不同部分的系统,以确保系统的稳定性和可靠性。在 Bulkheads 模式下,系统中的不同部分被隔离开来,一部分的故障或负载不会影响其他部分的运行。 4 | -------------------------------------------------------------------------------- /stability/bulkhead/bulkhead.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func worker(name string, wg *sync.WaitGroup) { 10 | defer wg.Done() 11 | 12 | fmt.Println("Worker", name, "is starting...") 13 | time.Sleep(2 * time.Second) 14 | fmt.Println("Worker", name, "is done.") 15 | } 16 | 17 | func main() { 18 | var wg sync.WaitGroup 19 | wg.Add(3) 20 | 21 | go worker("A", &wg) 22 | go worker("B", &wg) 23 | go worker("C", &wg) 24 | 25 | wg.Wait() 26 | fmt.Println("All workers have finished.") 27 | } 28 | -------------------------------------------------------------------------------- /stability/circuit/README.md: -------------------------------------------------------------------------------- 1 | ## 断路器模式 2 | 3 | 断路器模式(Circuit-Breaker Pattern,有的文章也叫熔断模式)用于在分布式系统中处理故障和延迟问题。该模式工作原理类似于电气工程中的断路器,当系统出现故障或延迟情况时,断路器会打开并暂时中断对故障服务的访问,从而保护系统免受进一步破坏。 4 | -------------------------------------------------------------------------------- /stability/circuit/circuit.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func serviceCall() error { 9 | // 模拟调用远程服务 10 | if time.Now().Second()%2 == 0 { 11 | return fmt.Errorf("Service Error") 12 | } 13 | return nil 14 | } 15 | 16 | func main() { 17 | breaker := false 18 | failCount := 0 19 | 20 | for i := 0; i < 10; i++ { 21 | if failCount >= 3 { 22 | breaker = true 23 | fmt.Println("Circuit-Breaker is open") 24 | } 25 | 26 | if breaker { 27 | fmt.Println("Service is unavailable") 28 | time.Sleep(2 * time.Second) // 等待断路器重置 29 | failCount = 0 30 | breaker = false 31 | continue 32 | } 33 | 34 | err := serviceCall() 35 | if err != nil { 36 | fmt.Println("Service call failed:", err) 37 | failCount++ 38 | } else { 39 | fmt.Println("Service call successful") 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /stability/circuit/example/README.md: -------------------------------------------------------------------------------- 1 | # 熔断模式 2 | 3 | Circuit Breaker Pattern 也叫断路器模式,断路器设计模式是故障优先,一种处理失败的安全机制,防止更大的失败。 4 | 5 | 断路器类似于电路连接时防止着火的保险丝,当向电网输送了大量的电能时,会导致电线加热和燃烧,会导致供电临时中断。 6 | 7 | 熔断用于保护流量过大,是一种保护行为。 8 | 9 | ![熔断器状态机](../../images/breaker-state-machine.png) 10 | 11 | 状态变化流: 12 | 13 | ![状态变化流](../../images/breaker-state-machine-flow.png) 14 | 15 | 一些关键角色: 16 | 17 | ## Operation Counter 操作计数器 18 | 19 | 是一个简单的计数器,记录的成功和失败的状态。 20 | 21 | ## Circuit Breaker 断路器 22 | 23 | 电路连续故障,并且超过指定的阈值,它将返回一个快速错误,一段时间后,才会重试请求。 24 | 25 | ## Context 26 | 27 | 上下文用于传递参数. 28 | 29 | 参考: 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /stability/circuit/example/breaker/breaker.go: -------------------------------------------------------------------------------- 1 | package breaker 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | "sync/atomic" 7 | "time" 8 | ) 9 | 10 | // ErrBreakerOpen is the error returned from Run() when the function is not executed 11 | // because the breaker is currently open. 12 | var ErrBreakerOpen = errors.New("circuit breaker is open") 13 | 14 | const ( 15 | closed uint32 = iota 16 | open 17 | halfOpen 18 | ) 19 | 20 | // Breaker implements the circuit-breaker resiliency pattern 21 | type Breaker struct { 22 | errorThreshold, successThreshold int 23 | timeout time.Duration 24 | lock sync.Mutex 25 | state uint32 26 | errors, successes int 27 | lastError time.Time 28 | } 29 | 30 | // New constructs a new circuit-breaker that starts closed. 31 | // From closed, the breaker opens if "errorThreshold" errors are seen 32 | // without an error-free period of at least "timeout". From open, the 33 | // breaker half-closes after "timeout". From half-open, the breaker closes 34 | // after "successThreshold" consecutive successes, or opens on a single error. 35 | func New(errorThreshold, successThreshold int, timeout time.Duration) *Breaker { 36 | return &Breaker{ 37 | errorThreshold: errorThreshold, 38 | successThreshold: successThreshold, 39 | timeout: timeout, 40 | } 41 | } 42 | 43 | // Run will either return ErrBreakerOpen immediately if the circuit-breaker is 44 | // already open, or it will run the given function and pass along its return 45 | // value. It is safe to call Run concurrently on the same Breaker. 46 | func (b *Breaker) Run(work func() error) error { 47 | state := atomic.LoadUint32(&b.state) 48 | 49 | if state == open { 50 | return ErrBreakerOpen 51 | } 52 | 53 | return b.doWork(state, work) 54 | } 55 | 56 | // Go will either return ErrBreakerOpen immediately if the circuit-breaker is 57 | // already open, or it will run the given function in a separate goroutine. 58 | // If the function is run, Go will return nil immediately, and will *not* return 59 | // the return value of the function. It is safe to call Go concurrently on the 60 | // same Breaker. 61 | func (b *Breaker) Go(work func() error) error { 62 | state := atomic.LoadUint32(&b.state) 63 | 64 | if state == open { 65 | return ErrBreakerOpen 66 | } 67 | 68 | // errcheck complains about ignoring the error return value, but 69 | // that's on purpose; if you want an error from a goroutine you have to 70 | // get it over a channel or something 71 | go b.doWork(state, work) 72 | 73 | return nil 74 | } 75 | 76 | func (b *Breaker) doWork(state uint32, work func() error) error { 77 | var panicValue interface{} 78 | 79 | result := func() error { 80 | defer func() { 81 | panicValue = recover() 82 | }() 83 | return work() 84 | }() 85 | 86 | if result == nil && panicValue == nil && state == closed { 87 | // short-circuit the normal, success path without contending 88 | // on the lock 89 | return nil 90 | } 91 | 92 | // oh well, I guess we have to contend on the lock 93 | b.processResult(result, panicValue) 94 | 95 | if panicValue != nil { 96 | // as close as Go lets us come to a "rethrow" although unfortunately 97 | // we lose the original panicing location 98 | panic(panicValue) 99 | } 100 | 101 | return result 102 | } 103 | 104 | func (b *Breaker) processResult(result error, panicValue interface{}) { 105 | b.lock.Lock() 106 | defer b.lock.Unlock() 107 | 108 | if result == nil && panicValue == nil { 109 | if b.state == halfOpen { 110 | b.successes++ 111 | if b.successes == b.successThreshold { 112 | b.closeBreaker() 113 | } 114 | } 115 | } else { 116 | if b.errors > 0 { 117 | expiry := b.lastError.Add(b.timeout) 118 | if time.Now().After(expiry) { 119 | b.errors = 0 120 | } 121 | } 122 | 123 | switch b.state { 124 | case closed: 125 | b.errors++ 126 | if b.errors == b.errorThreshold { 127 | b.openBreaker() 128 | } else { 129 | b.lastError = time.Now() 130 | } 131 | case halfOpen: 132 | b.openBreaker() 133 | } 134 | } 135 | } 136 | 137 | func (b *Breaker) openBreaker() { 138 | b.changeState(open) 139 | go b.timer() 140 | } 141 | 142 | func (b *Breaker) closeBreaker() { 143 | b.changeState(closed) 144 | } 145 | 146 | func (b *Breaker) timer() { 147 | time.Sleep(b.timeout) 148 | 149 | b.lock.Lock() 150 | defer b.lock.Unlock() 151 | 152 | b.changeState(halfOpen) 153 | } 154 | 155 | func (b *Breaker) changeState(newState uint32) { 156 | b.errors = 0 157 | b.successes = 0 158 | atomic.StoreUint32(&b.state, newState) 159 | } 160 | -------------------------------------------------------------------------------- /stability/circuit/example/breaker/breaker_test.go: -------------------------------------------------------------------------------- 1 | package breaker 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | var errSomeError = errors.New("errSomeError") 10 | 11 | func alwaysPanics() error { 12 | panic("foo") 13 | } 14 | 15 | func returnsError() error { 16 | return errSomeError 17 | } 18 | 19 | func returnsSuccess() error { 20 | return nil 21 | } 22 | 23 | func TestExampleBreaker(t *testing.T) { 24 | breaker := New(3, 1, 5*time.Second) 25 | 26 | for { 27 | result := breaker.Run(func() error { 28 | // communicate with some external service and 29 | // return an error if the communication failed 30 | return nil 31 | }) 32 | 33 | switch result { 34 | case nil: 35 | // success! 36 | case ErrBreakerOpen: 37 | // our function wasn't run because the breaker was open 38 | default: 39 | // some other error 40 | } 41 | } 42 | } 43 | 44 | func TestBreakerErrorExpiry(t *testing.T) { 45 | breaker := New(2, 1, 1*time.Second) 46 | 47 | for i := 0; i < 3; i++ { 48 | if err := breaker.Run(returnsError); err != errSomeError { 49 | t.Error(err) 50 | } 51 | time.Sleep(1 * time.Second) 52 | } 53 | 54 | for i := 0; i < 3; i++ { 55 | if err := breaker.Go(returnsError); err != nil { 56 | t.Error(err) 57 | } 58 | time.Sleep(1 * time.Second) 59 | } 60 | } 61 | 62 | func TestBreakerPanicsCountAsErrors(t *testing.T) { 63 | breaker := New(3, 2, 1*time.Second) 64 | 65 | // three errors opens the breaker 66 | for i := 0; i < 3; i++ { 67 | func() { 68 | defer func() { 69 | val := recover() 70 | if val.(string) != "foo" { 71 | t.Error("incorrect panic") 72 | } 73 | }() 74 | if err := breaker.Run(alwaysPanics); err != nil { 75 | t.Error(err) 76 | } 77 | t.Error("shouldn't get here") 78 | }() 79 | } 80 | 81 | // breaker is open 82 | for i := 0; i < 5; i++ { 83 | if err := breaker.Run(returnsError); err != ErrBreakerOpen { 84 | t.Error(err) 85 | } 86 | } 87 | } 88 | 89 | func TestBreakerStateTransitions(t *testing.T) { 90 | breaker := New(3, 2, 1*time.Second) 91 | 92 | // three errors opens the breaker 93 | for i := 0; i < 3; i++ { 94 | if err := breaker.Run(returnsError); err != errSomeError { 95 | t.Error(err) 96 | } 97 | } 98 | 99 | // breaker is open 100 | for i := 0; i < 5; i++ { 101 | if err := breaker.Run(returnsError); err != ErrBreakerOpen { 102 | t.Error(err) 103 | } 104 | } 105 | 106 | // wait for it to half-close 107 | time.Sleep(2 * time.Second) 108 | // one success works, but is not enough to fully close 109 | if err := breaker.Run(returnsSuccess); err != nil { 110 | t.Error(err) 111 | } 112 | // error works, but re-opens immediately 113 | if err := breaker.Run(returnsError); err != errSomeError { 114 | t.Error(err) 115 | } 116 | // breaker is open 117 | if err := breaker.Run(returnsError); err != ErrBreakerOpen { 118 | t.Error(err) 119 | } 120 | 121 | // wait for it to half-close 122 | time.Sleep(2 * time.Second) 123 | // two successes is enough to close it for good 124 | for i := 0; i < 2; i++ { 125 | if err := breaker.Run(returnsSuccess); err != nil { 126 | t.Error(err) 127 | } 128 | } 129 | // error works 130 | if err := breaker.Run(returnsError); err != errSomeError { 131 | t.Error(err) 132 | } 133 | // breaker is still closed 134 | if err := breaker.Run(returnsSuccess); err != nil { 135 | t.Error(err) 136 | } 137 | } 138 | 139 | func TestBreakerAsyncStateTransitions(t *testing.T) { 140 | breaker := New(3, 2, 1*time.Second) 141 | 142 | // three errors opens the breaker 143 | for i := 0; i < 3; i++ { 144 | if err := breaker.Go(returnsError); err != nil { 145 | t.Error(err) 146 | } 147 | } 148 | 149 | // just enough to yield the scheduler and let the goroutines work off 150 | time.Sleep(1 * time.Millisecond) 151 | 152 | // breaker is open 153 | for i := 0; i < 5; i++ { 154 | if err := breaker.Go(returnsError); err != ErrBreakerOpen { 155 | t.Error(err) 156 | } 157 | } 158 | 159 | // wait for it to half-close 160 | time.Sleep(2 * time.Second) 161 | // one success works, but is not enough to fully close 162 | if err := breaker.Go(returnsSuccess); err != nil { 163 | t.Error(err) 164 | } 165 | // error works, but re-opens immediately 166 | if err := breaker.Go(returnsError); err != nil { 167 | t.Error(err) 168 | } 169 | // just enough to yield the scheduler and let the goroutines work off 170 | time.Sleep(1 * time.Millisecond) 171 | // breaker is open 172 | if err := breaker.Go(returnsError); err != ErrBreakerOpen { 173 | t.Error(err) 174 | } 175 | 176 | // wait for it to half-close 177 | time.Sleep(2 * time.Second) 178 | // two successes is enough to close it for good 179 | for i := 0; i < 2; i++ { 180 | if err := breaker.Go(returnsSuccess); err != nil { 181 | t.Error(err) 182 | } 183 | } 184 | // just enough to yield the scheduler and let the goroutines work off 185 | time.Sleep(1 * time.Millisecond) 186 | // error works 187 | if err := breaker.Go(returnsError); err != nil { 188 | t.Error(err) 189 | } 190 | // just enough to yield the scheduler and let the goroutines work off 191 | time.Sleep(1 * time.Millisecond) 192 | // breaker is still closed 193 | if err := breaker.Go(returnsSuccess); err != nil { 194 | t.Error(err) 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /stability/circuit/example/breaker_options.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: https://github.com/crazybber 3 | * @Author: Edward 4 | * @Date: 2020-06-02 23:57:40 5 | * @Last Modified by: Edward 6 | * @Last Modified time: 2020-06-03 23:50:17 7 | */ 8 | 9 | package circuit 10 | 11 | import ( 12 | "context" 13 | "time" 14 | ) 15 | 16 | // BreakConditionWatcher check state 17 | type BreakConditionWatcher func(state State, cnter counters) bool 18 | 19 | // StateChangedEventHandler set event handle 20 | type StateChangedEventHandler func(name string, from State, to State) 21 | 22 | // Option set Options 23 | type Option func(opts *Options) 24 | 25 | // Options for breaker 26 | type Options struct { 27 | Name string 28 | Expiry time.Time 29 | Interval, Timeout time.Duration 30 | MaxRequests uint32 31 | CanOpen BreakConditionWatcher //是否应该断开电路(打开电路开关) 32 | CanClose BreakConditionWatcher //if we should close switch 33 | OnStateChanged StateChangedEventHandler 34 | ShoulderHalfToOpen uint32 35 | Ctx context.Context 36 | } 37 | 38 | // ActionName of breaker 39 | func ActionName(name string) Option { 40 | return func(opts *Options) { 41 | opts.Name = name 42 | } 43 | } 44 | 45 | // Interval of breaker 46 | func Interval(interval time.Duration) Option { 47 | return func(opts *Options) { 48 | opts.Interval = interval 49 | } 50 | } 51 | 52 | // Timeout of breaker 53 | func Timeout(timeout time.Duration) Option { 54 | return func(opts *Options) { 55 | opts.Timeout = timeout 56 | } 57 | } 58 | 59 | // MaxRequests is the maximum number of requests allowed to pass through 60 | // when the CircuitBreaker is half-open. 61 | // If MaxRequests is 0, the CircuitBreaker allows only 1 request. 62 | 63 | // MaxRequests of breaker 64 | func MaxRequests(maxRequests uint32) Option { 65 | return func(opts *Options) { 66 | opts.MaxRequests = maxRequests 67 | } 68 | } 69 | 70 | // WithShoulderHalfToOpen of breaker 71 | func WithShoulderHalfToOpen(shoulderHalfToOpen uint32) Option { 72 | return func(opts *Options) { 73 | opts.ShoulderHalfToOpen = shoulderHalfToOpen 74 | } 75 | } 76 | 77 | // Expiry of breaker 78 | func Expiry(expiry time.Time) Option { 79 | return func(opts *Options) { 80 | opts.Expiry = expiry 81 | } 82 | } 83 | 84 | // WithStateChanged set handle of ChangedHandle 85 | func WithStateChanged(handler StateChangedEventHandler) Option { 86 | return func(opts *Options) { 87 | opts.OnStateChanged = handler 88 | } 89 | } 90 | 91 | // WithBreakCondition check traffic state ,to see if request can go 92 | func WithBreakCondition(whenCondition BreakConditionWatcher) Option { 93 | return func(opts *Options) { 94 | opts.CanOpen = whenCondition 95 | } 96 | } 97 | 98 | // WithCloseCondition check traffic state ,to see if request can go 99 | func WithCloseCondition(whenCondition BreakConditionWatcher) Option { 100 | return func(opts *Options) { 101 | opts.CanClose = whenCondition 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /stability/circuit/example/circuit_breaker_adv.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: https://github.com/crazybber 3 | * @Author: Edward 4 | * @Date: 2020-05-10 22:00:58 5 | * @Last Modified by: Edward 6 | * @Last Modified time: 2020-06-03 23:54:29 7 | */ 8 | 9 | package circuit 10 | 11 | import ( 12 | "context" 13 | "errors" 14 | "fmt" 15 | "sync" 16 | "time" 17 | ) 18 | 19 | //////////////////////////////// 20 | ///使用HTTP请求的例子 21 | //每个搜索引擎时时刻刻都会遇到超大规模的请求的流量. 22 | //这里演示一个复杂一点的例子,同时使用Option 模式 23 | 24 | // ErrServiceUnavailable for error 25 | var ( 26 | ErrTooManyRequests = errors.New("too many requests") 27 | ErrServiceUnavailable = errors.New("service unavailable") 28 | FailureThreshold = 10 //最大失败次数--->失败阈值 29 | ) 30 | 31 | // 默认的超时时间 32 | const ( 33 | defaultTimeout = time.Second * 30 34 | defaultSuccessThreshold = 2 35 | ) 36 | 37 | //////////////////////////////// 38 | //way 2 对象式断路器 39 | // 高级模式 40 | // 支持多工作者模式 41 | //////////////////////////////// 42 | 43 | // RequestBreaker for protection 44 | type RequestBreaker struct { 45 | options Options 46 | mutex sync.Mutex 47 | state State 48 | cnter counters 49 | preState State 50 | } 51 | 52 | // NewRequestBreaker return a breaker 53 | func NewRequestBreaker(opts ...Option) *RequestBreaker { 54 | 55 | defaultOptions := Options{ 56 | Name: "defaultBreakerName", 57 | Expiry: time.Now().Add(time.Second * 20), 58 | Interval: time.Second * 10, // interval to check closed status,default 10 seconds 59 | Timeout: time.Second * 60, //timeout to check open, default 60 seconds 60 | MaxRequests: 5, 61 | CanOpen: func(current State, cnter counters) bool { return cnter.ConsecutiveFailures > 2 }, 62 | CanClose: func(current State, cnter counters) bool { return cnter.ConsecutiveSuccesses > 2 }, 63 | OnStateChanged: func(name string, fromPre State, toCurrent State) {}, 64 | } 65 | 66 | for _, setOption := range opts { 67 | setOption(&defaultOptions) 68 | 69 | } 70 | 71 | return &RequestBreaker{ 72 | options: defaultOptions, 73 | cnter: counters{}, 74 | state: StateUnknown, 75 | preState: StateUnknown, 76 | } 77 | } 78 | 79 | func (rb *RequestBreaker) changeStateTo(state State) { 80 | rb.preState = rb.state 81 | rb.state = state 82 | rb.cnter.Reset() 83 | } 84 | 85 | func (rb *RequestBreaker) beforeRequest() error { 86 | 87 | rb.mutex.Lock() 88 | defer rb.mutex.Unlock() 89 | fmt.Println("before do request:", rb.cnter.Total()) 90 | 91 | switch rb.state { 92 | case StateOpen: 93 | //如果是断开状态,并且超时了,转到半开状态,记录 94 | if rb.options.Expiry.Before(time.Now()) { 95 | rb.changeStateTo(StateHalfOpen) 96 | rb.options.Expiry = time.Now().Add(rb.options.Timeout) 97 | return nil 98 | } 99 | return ErrTooManyRequests 100 | case StateClosed: 101 | if rb.options.Expiry.Before(time.Now()) { 102 | rb.cnter.Reset() 103 | rb.options.Expiry = time.Now().Add(rb.options.Interval) 104 | } 105 | } 106 | 107 | return nil 108 | 109 | } 110 | 111 | // Do the given requested work if the RequestBreaker accepts it. 112 | // Do returns an error instantly if the RequestBreaker rejects the request. 113 | // Otherwise, Execute returns the result of the request. 114 | // If a panic occurs in the request, the RequestBreaker handles it as an error and causes the same panic again. 115 | func (rb *RequestBreaker) Do(work func(ctx context.Context) (interface{}, error)) (interface{}, error) { 116 | 117 | //before 118 | 119 | if err := rb.beforeRequest(); err != nil { 120 | return nil, err 121 | } 122 | 123 | //do work 124 | //do work from requested user 125 | result, err := work(rb.options.Ctx) 126 | 127 | //after work 128 | rb.afterRequest(err) 129 | 130 | return result, err 131 | } 132 | 133 | func (rb *RequestBreaker) afterRequest(resultErr error) { 134 | 135 | rb.mutex.Lock() 136 | defer rb.mutex.Unlock() 137 | //after 138 | fmt.Println("after do request:", rb.cnter.Total()) 139 | 140 | if resultErr != nil { 141 | //失败了,handle 失败 142 | rb.cnter.Count(FailureState, rb.preState == rb.state) 143 | switch rb.state { 144 | case StateHalfOpen, StateClosed: 145 | if rb.options.CanOpen(rb.state, rb.cnter) { 146 | rb.changeStateTo(StateOpen) //打开开关 147 | rb.options.OnStateChanged(rb.options.Name, rb.state, StateOpen) //关闭到打开 148 | } 149 | } 150 | } else { 151 | //success ! 152 | rb.cnter.Count(SuccessState, rb.preState == rb.state) 153 | 154 | switch rb.state { 155 | case StateHalfOpen: 156 | if rb.preState == StateOpen { 157 | // rb.changeStateTo(StateHalfOpen) //already handled in beforeRequest,Only fire StateChange Event 158 | rb.options.OnStateChanged(rb.options.Name, StateOpen, StateHalfOpen) //打开到半开 159 | } 160 | if rb.cnter.ConsecutiveSuccesses >= rb.options.ShoulderHalfToOpen { 161 | rb.changeStateTo(StateClosed) 162 | rb.options.Expiry = time.Now().Add(rb.options.Interval) 163 | rb.options.OnStateChanged(rb.options.Name, StateHalfOpen, StateClosed) //半开到关闭 164 | } 165 | 166 | } 167 | 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /stability/circuit/example/circuit_breaker_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: https://github.com/crazybber 3 | * @Author: Edward 4 | * @Date: 2020-05-11 10:55:28 5 | * @Last Modified by: Edward 6 | * @Last Modified time: 2020-05-22 17:21:06 7 | */ 8 | 9 | package circuit 10 | 11 | import ( 12 | "context" 13 | "fmt" 14 | "io/ioutil" 15 | "log" 16 | "net/http" 17 | "testing" 18 | ) 19 | 20 | var breaker *RequestBreaker 21 | 22 | var onStateChangeEvent = func(name string, from, to State) { 23 | fmt.Println("name:", name, "from:", from, "to", to) 24 | } 25 | 26 | var canOpenSwitch = func(current State, cnter counters) bool { 27 | 28 | if current == StateHalfOpen { 29 | return cnter.ConsecutiveFailures > 2 30 | } 31 | 32 | //失败率,可以由用户自己定义 33 | failureRatio := float64(cnter.TotalFailures) / float64(cnter.Requests) 34 | return cnter.Requests >= 3 && failureRatio >= 0.6 35 | } 36 | 37 | var canCloseSwitch = func(current State, cnter counters) bool { 38 | //失败率,可以由用户自己定义 39 | if cnter.ConsecutiveSuccesses > 2 { 40 | return true 41 | } 42 | // 43 | successRatio := float64(cnter.TotalFailures) / float64(cnter.Requests) 44 | return cnter.Requests >= 3 && successRatio >= 0.6 45 | } 46 | 47 | func TestObjectBreaker(t *testing.T) { 48 | 49 | jobToDo := func(ctx context.Context) (interface{}, error) { 50 | resp, err := http.Get("https://bing.com/robots.txt") 51 | if err != nil { 52 | return nil, err 53 | } 54 | defer resp.Body.Close() 55 | body, err := ioutil.ReadAll(resp.Body) 56 | if err != nil { 57 | return nil, err 58 | } 59 | return body, nil 60 | } 61 | 62 | breaker = NewRequestBreaker(ActionName("HTTP GET"), 63 | WithBreakCondition(canOpenSwitch), 64 | WithCloseCondition(canCloseSwitch), 65 | WithShoulderHalfToOpen(2), 66 | WithStateChanged(onStateChangeEvent)) 67 | 68 | body, err := breaker.Do(jobToDo) 69 | if err != nil { 70 | t.Fatal(err) 71 | } 72 | 73 | fmt.Println(string(body.([]byte))) 74 | 75 | log.Print("\nresult:", body.([]byte)) 76 | } 77 | 78 | func TestFunctionalBreaker(t *testing.T) { 79 | 80 | //something need to do 81 | jobToDo := func(ctx context.Context) error { 82 | resp, err := http.Get("https://bing.com/robots.txt") 83 | if err != nil { 84 | return err 85 | } 86 | defer resp.Body.Close() 87 | body, err := ioutil.ReadAll(resp.Body) 88 | if err != nil { 89 | return err 90 | } 91 | fmt.Println(string(body)) 92 | return nil 93 | } 94 | 95 | //wrapper and control job with a breaker 96 | circuitWork := Breaker(jobToDo, 2 /* failureThreshold */) 97 | 98 | params := context.TODO() 99 | 100 | // do the job as usually 101 | res := circuitWork(params) 102 | 103 | log.Print("\nresult:", res) 104 | 105 | } 106 | -------------------------------------------------------------------------------- /stability/circuit/example/circuit_counter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: https://github.com/crazybber 3 | * @Author: Edward 4 | * @Date: 2020-05-22 12:41:54 5 | * @Last Modified by: Edward 6 | * @Last Modified time: 2020-05-22 17:22:35 7 | */ 8 | 9 | package circuit 10 | 11 | import "time" 12 | 13 | //////////////////////////////// 14 | /// 计数器 用以维护断路器内部的状态 15 | /// 无论是对象式断路器还是函数式断路器 16 | /// 都要用到计数器 17 | //////////////////////////////// 18 | 19 | // State 断路器本身的状态的 20 | // State of switch int 21 | type State int 22 | 23 | // state for breaker 24 | const ( 25 | StateClosed State = iota //默认的闭合状态,可以正常执行业务 26 | StateHalfOpen 27 | StateOpen 28 | StateUnknown 29 | ) 30 | 31 | // OperationState of current 某一次操作的结果状态 32 | type OperationState int 33 | 34 | // ICounter interface 35 | type ICounter interface { 36 | Count(OperationState, bool) 37 | LastActivity() time.Time 38 | Reset() 39 | Total() uint32 40 | } 41 | 42 | type counters struct { 43 | Requests uint32 //连续的请求次数 44 | lastActivity time.Time 45 | TotalFailures uint32 46 | TotalSuccesses uint32 47 | ConsecutiveSuccesses uint32 48 | ConsecutiveFailures uint32 49 | } 50 | 51 | func (c *counters) Total() uint32 { 52 | return c.Requests 53 | } 54 | 55 | func (c *counters) LastActivity() time.Time { 56 | return c.lastActivity 57 | } 58 | 59 | func (c *counters) Reset() { 60 | ct := &counters{} 61 | ct.lastActivity = c.lastActivity 62 | c = ct 63 | } 64 | 65 | // Count the failure and success 66 | func (c *counters) Count(statue OperationState, isConsecutive bool) { 67 | 68 | switch statue { 69 | case FailureState: 70 | c.TotalFailures++ 71 | if isConsecutive || c.ConsecutiveFailures == 0 { 72 | c.ConsecutiveFailures++ 73 | } 74 | case SuccessState: 75 | c.TotalSuccesses++ 76 | if isConsecutive || c.ConsecutiveSuccesses == 0 { 77 | c.ConsecutiveSuccesses++ 78 | } 79 | } 80 | c.Requests++ 81 | c.lastActivity = time.Now() //更新活动时间 82 | // c.lastOpResult = statue 83 | //handle status change 84 | 85 | } 86 | -------------------------------------------------------------------------------- /stability/circuit/example/circuit_func_closure_basic.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: https://github.com/crazybber 3 | * @Author: Edward 4 | * @Date: 2020-05-22 12:42:34 5 | * @Last Modified by: Edward 6 | * @Last Modified time: 2020-05-22 17:21:40 7 | */ 8 | 9 | package circuit 10 | 11 | import ( 12 | "context" 13 | "time" 14 | ) 15 | 16 | //////////////////////////////// 17 | //way 1 简单的函数式断路器 18 | // 一个func实例作为一个Breaker 允许多个worker(即goroutine)同时访问 19 | // 当前简单场景下,只考虑单个worker情况下的连续请求 20 | // 当前的设计思路,非常简单: 21 | // 1、不考虑三种状态之间的转换,只靠两种状态,电路打开与电路关闭 22 | // 2、当累计失败到达一定失败次数就端开请求(打开电路),并延迟一定的时间再允许请求 23 | //////////////////////////////// 24 | 25 | // states of CircuitBreaker 26 | // states: closed --->open ---> half open --> closed 27 | const ( 28 | UnknownState OperationState = iota 29 | FailureState 30 | SuccessState 31 | ) 32 | 33 | type simpleCounter struct { 34 | lastOpResult OperationState 35 | lastActivity time.Time 36 | ConsecutiveSuccesses uint32 37 | ConsecutiveFailures uint32 38 | } 39 | 40 | func (c *simpleCounter) LastActivity() time.Time { 41 | return c.lastActivity 42 | } 43 | 44 | func (c *simpleCounter) Reset() { 45 | ct := &simpleCounter{} 46 | ct.lastActivity = c.lastActivity 47 | ct.lastOpResult = UnknownState 48 | c = ct 49 | } 50 | 51 | // Count the failure and success 52 | func (c *simpleCounter) Count(lastState OperationState) { 53 | 54 | switch lastState { 55 | case FailureState: 56 | c.ConsecutiveFailures++ 57 | case SuccessState: 58 | c.ConsecutiveSuccesses++ 59 | } 60 | c.lastActivity = time.Now() //更新活动时间 61 | c.lastOpResult = lastState 62 | //handle status change 63 | } 64 | 65 | // Circuit of action stream,this is actually to do something. 66 | // Circuit hold the really action 67 | type Circuit func(context.Context) error 68 | 69 | // 失败达到阈值后,过两秒重试 70 | var canRetry = func(cnt simpleCounter, failureThreshold uint32) bool { 71 | backoffLevel := cnt.ConsecutiveFailures - failureThreshold 72 | // Calculates when should the circuit breaker resume propagating requests 73 | // to the service 74 | shouldRetryAt := cnt.LastActivity().Add(time.Second << backoffLevel) 75 | return time.Now().After(shouldRetryAt) 76 | } 77 | 78 | // Breaker return a closure wrapper to hold Circuit Request 79 | func Breaker(c Circuit, failureThreshold uint32) Circuit { 80 | 81 | //闭包内部的全局计数器 和状态标志 82 | cnt := simpleCounter{} 83 | 84 | //ctx can be used hold parameters 85 | return func(ctx context.Context) error { 86 | 87 | //阻止请求 88 | if cnt.ConsecutiveFailures >= failureThreshold { 89 | if !canRetry(cnt, failureThreshold) { 90 | // Fails fast instead of propagating requests to the circuit since 91 | // not enough time has passed since the last failure to retry 92 | return ErrServiceUnavailable 93 | } 94 | //reset mark for failures 95 | cnt.ConsecutiveFailures = 0 96 | } 97 | 98 | // Unless the failure threshold is exceeded the wrapped service mimics the 99 | // old behavior and the difference in behavior is seen after consecutive failures 100 | if err := c(ctx); err != nil { 101 | //连续失败会增大backoff 时间 102 | cnt.Count(FailureState) 103 | return err 104 | } 105 | 106 | cnt.Count(SuccessState) 107 | return nil 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /stability/circuit/example/gobreaker/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | 说明,这是一个由sony的作者完整实现的breaker模式,可以用于生产环境. 4 | -------------------------------------------------------------------------------- /stability/circuit/example/gobreaker/gobreaker.go: -------------------------------------------------------------------------------- 1 | // Package gobreaker implements the Circuit Breaker pattern. 2 | // See https://msdn.microsoft.com/en-us/library/dn589784.aspx. 3 | package gobreaker 4 | 5 | import ( 6 | "errors" 7 | "fmt" 8 | "sync" 9 | "time" 10 | ) 11 | 12 | // State is a type that represents a state of CircuitBreaker. 13 | type State int 14 | 15 | // These constants are states of CircuitBreaker. 16 | const ( 17 | StateClosed State = iota 18 | StateHalfOpen 19 | StateOpen 20 | ) 21 | 22 | var ( 23 | // ErrTooManyRequests is returned when the CB state is half open and the requests count is over the cb maxRequests 24 | ErrTooManyRequests = errors.New("too many requests") 25 | // ErrOpenState is returned when the CB state is open 26 | ErrOpenState = errors.New("circuit breaker is open") 27 | ) 28 | 29 | // String implements stringer interface. 30 | func (s State) String() string { 31 | switch s { 32 | case StateClosed: 33 | return "closed" 34 | case StateHalfOpen: 35 | return "half-open" 36 | case StateOpen: 37 | return "open" 38 | default: 39 | return fmt.Sprintf("unknown state: %d", s) 40 | } 41 | } 42 | 43 | // Counts holds the numbers of requests and their successes/failures. 44 | // CircuitBreaker clears the internal Counts either 45 | // on the change of the state or at the closed-state intervals. 46 | // Counts ignores the results of the requests sent before clearing. 47 | type Counts struct { 48 | Requests uint32 49 | TotalSuccesses uint32 50 | TotalFailures uint32 51 | ConsecutiveSuccesses uint32 52 | ConsecutiveFailures uint32 53 | } 54 | 55 | func (c *Counts) onRequest() { 56 | c.Requests++ 57 | } 58 | 59 | func (c *Counts) onSuccess() { 60 | c.TotalSuccesses++ 61 | c.ConsecutiveSuccesses++ 62 | c.ConsecutiveFailures = 0 63 | } 64 | 65 | func (c *Counts) onFailure() { 66 | c.TotalFailures++ 67 | c.ConsecutiveFailures++ 68 | c.ConsecutiveSuccesses = 0 69 | } 70 | 71 | func (c *Counts) clear() { 72 | c.Requests = 0 73 | c.TotalSuccesses = 0 74 | c.TotalFailures = 0 75 | c.ConsecutiveSuccesses = 0 76 | c.ConsecutiveFailures = 0 77 | } 78 | 79 | // Settings configures CircuitBreaker: 80 | // 81 | // Name is the name of the CircuitBreaker. 82 | // 83 | // MaxRequests is the maximum number of requests allowed to pass through 84 | // when the CircuitBreaker is half-open. 85 | // If MaxRequests is 0, the CircuitBreaker allows only 1 request. 86 | // 87 | // Interval is the cyclic period of the closed state 88 | // for the CircuitBreaker to clear the internal Counts. 89 | // If Interval is less than or equal to 0, the CircuitBreaker doesn't clear internal Counts during the closed state. 90 | // 91 | // Timeout is the period of the open state, 92 | // after which the state of the CircuitBreaker becomes half-open. 93 | // If Timeout is less than or equal to 0, the timeout value of the CircuitBreaker is set to 60 seconds. 94 | // 95 | // ReadyToTrip is called with a copy of Counts whenever a request fails in the closed state. 96 | // If ReadyToTrip returns true, the CircuitBreaker will be placed into the open state. 97 | // If ReadyToTrip is nil, default ReadyToTrip is used. 98 | // Default ReadyToTrip returns true when the number of consecutive failures is more than 5. 99 | // 100 | // OnStateChange is called whenever the state of the CircuitBreaker changes. 101 | type Settings struct { 102 | Name string 103 | MaxRequests uint32 104 | Interval time.Duration 105 | Timeout time.Duration 106 | ReadyToTrip func(counts Counts) bool 107 | OnStateChange func(name string, from State, to State) 108 | } 109 | 110 | // CircuitBreaker is a state machine to prevent sending requests that are likely to fail. 111 | type CircuitBreaker struct { 112 | name string 113 | maxRequests uint32 114 | interval time.Duration 115 | timeout time.Duration 116 | readyToTrip func(counts Counts) bool 117 | onStateChange func(name string, from State, to State) 118 | 119 | mutex sync.Mutex 120 | state State 121 | generation uint64 122 | counts Counts 123 | expiry time.Time 124 | } 125 | 126 | // TwoStepCircuitBreaker is like CircuitBreaker but instead of surrounding a function 127 | // with the breaker functionality, it only checks whether a request can proceed and 128 | // expects the caller to report the outcome in a separate step using a callback. 129 | type TwoStepCircuitBreaker struct { 130 | cb *CircuitBreaker 131 | } 132 | 133 | // NewCircuitBreaker returns a new CircuitBreaker configured with the given Settings. 134 | func NewCircuitBreaker(st Settings) *CircuitBreaker { 135 | cb := new(CircuitBreaker) 136 | 137 | cb.name = st.Name 138 | cb.onStateChange = st.OnStateChange 139 | 140 | if st.MaxRequests == 0 { 141 | cb.maxRequests = 1 142 | } else { 143 | cb.maxRequests = st.MaxRequests 144 | } 145 | 146 | if st.Interval <= 0 { 147 | cb.interval = defaultInterval 148 | } else { 149 | cb.interval = st.Interval 150 | } 151 | 152 | if st.Timeout <= 0 { 153 | cb.timeout = defaultTimeout 154 | } else { 155 | cb.timeout = st.Timeout 156 | } 157 | 158 | if st.ReadyToTrip == nil { 159 | cb.readyToTrip = defaultReadyToTrip 160 | } else { 161 | cb.readyToTrip = st.ReadyToTrip 162 | } 163 | 164 | cb.toNewGeneration(time.Now()) 165 | 166 | return cb 167 | } 168 | 169 | // NewTwoStepCircuitBreaker returns a new TwoStepCircuitBreaker configured with the given Settings. 170 | func NewTwoStepCircuitBreaker(st Settings) *TwoStepCircuitBreaker { 171 | return &TwoStepCircuitBreaker{ 172 | cb: NewCircuitBreaker(st), 173 | } 174 | } 175 | 176 | const defaultInterval = time.Duration(0) * time.Second 177 | const defaultTimeout = time.Duration(60) * time.Second 178 | 179 | // 5 Consecutive Failures will break 180 | func defaultReadyToTrip(counts Counts) bool { 181 | return counts.ConsecutiveFailures > 5 182 | } 183 | 184 | // Name returns the name of the CircuitBreaker. 185 | func (cb *CircuitBreaker) Name() string { 186 | return cb.name 187 | } 188 | 189 | // State returns the current state of the CircuitBreaker. 190 | func (cb *CircuitBreaker) State() State { 191 | cb.mutex.Lock() 192 | defer cb.mutex.Unlock() 193 | 194 | now := time.Now() 195 | state, _ := cb.currentState(now) 196 | return state 197 | } 198 | 199 | // Execute runs the given request if the CircuitBreaker accepts it. 200 | // Execute returns an error instantly if the CircuitBreaker rejects the request. 201 | // Otherwise, Execute returns the result of the request. 202 | // If a panic occurs in the request, the CircuitBreaker handles it as an error 203 | // and causes the same panic again. 204 | func (cb *CircuitBreaker) Execute(req func() (interface{}, error)) (interface{}, error) { 205 | generation, err := cb.beforeRequest() 206 | if err != nil { 207 | return nil, err 208 | } 209 | 210 | defer func() { 211 | e := recover() 212 | if e != nil { 213 | cb.afterRequest(generation, false) 214 | panic(e) 215 | } 216 | }() 217 | 218 | result, err := req() 219 | cb.afterRequest(generation, err == nil) 220 | return result, err 221 | } 222 | 223 | // Name returns the name of the TwoStepCircuitBreaker. 224 | func (tscb *TwoStepCircuitBreaker) Name() string { 225 | return tscb.cb.Name() 226 | } 227 | 228 | // State returns the current state of the TwoStepCircuitBreaker. 229 | func (tscb *TwoStepCircuitBreaker) State() State { 230 | return tscb.cb.State() 231 | } 232 | 233 | // Allow checks if a new request can proceed. It returns a callback that should be used to 234 | // register the success or failure in a separate step. If the circuit breaker doesn't allow 235 | // requests, it returns an error. 236 | func (tscb *TwoStepCircuitBreaker) Allow() (done func(success bool), err error) { 237 | generation, err := tscb.cb.beforeRequest() 238 | if err != nil { 239 | return nil, err 240 | } 241 | 242 | return func(success bool) { 243 | tscb.cb.afterRequest(generation, success) 244 | }, nil 245 | } 246 | 247 | func (cb *CircuitBreaker) beforeRequest() (uint64, error) { 248 | cb.mutex.Lock() 249 | defer cb.mutex.Unlock() 250 | 251 | now := time.Now() 252 | state, generation := cb.currentState(now) 253 | 254 | if state == StateOpen { 255 | return generation, ErrOpenState 256 | } else if state == StateHalfOpen && cb.counts.Requests >= cb.maxRequests { 257 | return generation, ErrTooManyRequests 258 | } 259 | 260 | cb.counts.onRequest() 261 | return generation, nil 262 | } 263 | 264 | func (cb *CircuitBreaker) afterRequest(before uint64, success bool) { 265 | cb.mutex.Lock() 266 | defer cb.mutex.Unlock() 267 | 268 | now := time.Now() 269 | state, generation := cb.currentState(now) 270 | if generation != before { 271 | return 272 | } 273 | 274 | if success { 275 | cb.onSuccess(state, now) 276 | } else { 277 | cb.onFailure(state, now) 278 | } 279 | } 280 | 281 | func (cb *CircuitBreaker) onSuccess(state State, now time.Time) { 282 | switch state { 283 | case StateClosed: 284 | cb.counts.onSuccess() 285 | case StateHalfOpen: 286 | cb.counts.onSuccess() 287 | if cb.counts.ConsecutiveSuccesses >= cb.maxRequests { 288 | cb.setState(StateClosed, now) 289 | } 290 | } 291 | } 292 | 293 | func (cb *CircuitBreaker) onFailure(state State, now time.Time) { 294 | switch state { 295 | case StateClosed: 296 | cb.counts.onFailure() 297 | if cb.readyToTrip(cb.counts) { 298 | cb.setState(StateOpen, now) 299 | } 300 | case StateHalfOpen: 301 | cb.setState(StateOpen, now) 302 | } 303 | } 304 | 305 | func (cb *CircuitBreaker) currentState(now time.Time) (State, uint64) { 306 | switch cb.state { 307 | case StateClosed: 308 | if !cb.expiry.IsZero() && cb.expiry.Before(now) { 309 | cb.toNewGeneration(now) 310 | } 311 | case StateOpen: 312 | if cb.expiry.Before(now) { 313 | cb.setState(StateHalfOpen, now) 314 | } 315 | } 316 | return cb.state, cb.generation 317 | } 318 | 319 | func (cb *CircuitBreaker) setState(state State, now time.Time) { 320 | if cb.state == state { 321 | return 322 | } 323 | 324 | prev := cb.state 325 | cb.state = state 326 | 327 | cb.toNewGeneration(now) 328 | 329 | if cb.onStateChange != nil { 330 | cb.onStateChange(cb.name, prev, state) 331 | } 332 | } 333 | 334 | func (cb *CircuitBreaker) toNewGeneration(now time.Time) { 335 | cb.generation++ 336 | cb.counts.clear() 337 | 338 | var zero time.Time 339 | switch cb.state { 340 | case StateClosed: 341 | if cb.interval == 0 { 342 | cb.expiry = zero 343 | } else { 344 | cb.expiry = now.Add(cb.interval) 345 | } 346 | case StateOpen: 347 | cb.expiry = now.Add(cb.timeout) 348 | default: // StateHalfOpen 349 | cb.expiry = zero 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /stability/circuit/example/gobreaker/gobreaker_example_test.go: -------------------------------------------------------------------------------- 1 | package gobreaker 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | "testing" 8 | ) 9 | 10 | var cb *CircuitBreaker 11 | 12 | func TestGoBreaker(t *testing.T) { 13 | 14 | initBreaker() 15 | 16 | body, err := Get("https://bing.com/robots.txt") 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | 21 | fmt.Println(string(body)) 22 | } 23 | 24 | func initBreaker() { 25 | var st Settings 26 | st.Name = "HTTP GET" 27 | st.ReadyToTrip = func(counts Counts) bool { 28 | failureRatio := float64(counts.TotalFailures) / float64(counts.Requests) 29 | return counts.Requests >= 3 && failureRatio >= 0.6 30 | } 31 | 32 | cb = NewCircuitBreaker(st) 33 | } 34 | 35 | // Get wraps http.Get in CircuitBreaker. 36 | func Get(url string) ([]byte, error) { 37 | body, err := cb.Execute(func() (interface{}, error) { 38 | resp, err := http.Get(url) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | defer resp.Body.Close() 44 | body, err := ioutil.ReadAll(resp.Body) 45 | if err != nil { 46 | return nil, err 47 | } 48 | 49 | return body, nil 50 | }) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | return body.([]byte), nil 56 | 57 | } 58 | -------------------------------------------------------------------------------- /stability/deadline/README.md: -------------------------------------------------------------------------------- 1 | ## 截止期限模式 2 | 3 | 截止期限模式(Deadline Pattern)用于在处理任务时设置截止期限,确保任务在规定的时间内完成。该模式在分布式系统和并发编程中经常用于处理超时和任务执行时间限制的情况。 4 | -------------------------------------------------------------------------------- /stability/deadline/deadline.go: -------------------------------------------------------------------------------- 1 | // Package deadline implements deadline (also known as "timeout") resiliency pattern for Go. 2 | package deadline 3 | 4 | import ( 5 | "errors" 6 | "time" 7 | ) 8 | 9 | // ErrTimedOut is the error returned from Run when the Worker expires. 10 | var ErrTimedOut = errors.New("timed out waiting for function to finish") 11 | 12 | // Worker implements the Deadline/timeout resiliency pattern. 13 | // worker do the target job 14 | type Worker struct { 15 | timeout time.Duration 16 | action string 17 | } 18 | 19 | // New create a new Worker with the given timeout.and tile 20 | func New(timeout time.Duration, someActionTitle string) *Worker { 21 | return &Worker{ 22 | timeout: timeout, 23 | action: someActionTitle, 24 | } 25 | } 26 | 27 | // Run runs the given function, passing it a stopper channel. If the Worker passes before 28 | // the function finishes executing, Run returns ErrTimeOut to the caller and closes the stopper 29 | // channel so that the work function can attempt to exit gracefully. It does not (and cannot) 30 | // simply kill the running function, so if it doesn't respect the stopper channel then it may 31 | // keep running after the Worker passes. If the function finishes before the Worker, then 32 | // the return value of the function is returned from Run. 33 | func (d *Worker) Run(work func(stopperSignal chan error) error) error { 34 | 35 | result := make(chan error) 36 | //we can stop the work in advance 37 | stopper := make(chan error, 1) 38 | 39 | go func() { 40 | value := work(stopper) 41 | select { 42 | case result <- value: 43 | case stopError := <-stopper: 44 | result <- stopError 45 | } 46 | }() 47 | 48 | //handle result 49 | 50 | select { 51 | case ret := <-result: 52 | return ret 53 | case <-time.After(d.timeout): 54 | close(stopper) 55 | return ErrTimedOut 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /stability/deadline/deadline_test.go: -------------------------------------------------------------------------------- 1 | package deadline 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func workerTakes5ms(stopper chan error) error { 11 | fmt.Println("i'm doing this job in 5ms") 12 | time.Sleep(5 * time.Millisecond) 13 | return nil 14 | } 15 | 16 | func workerTakes20ms(stopper chan error) error { 17 | fmt.Println("i'm doing this job in 20ms,so work will timeout") 18 | time.Sleep(20 * time.Millisecond) 19 | return nil 20 | } 21 | 22 | func cancelWork(stopper chan error) error { 23 | fmt.Println("i'm doing this job") 24 | stopper <- errors.New("canceled job") //cancel job 25 | time.Sleep(5 * time.Millisecond) 26 | fmt.Println("job canceled") 27 | return nil 28 | } 29 | 30 | func returnsError(stopper chan error) error { 31 | fmt.Println("i'm doing this job but error occurred") 32 | return errors.New("foo") 33 | } 34 | 35 | func TestMultiDeadline(t *testing.T) { 36 | dl := New(15*time.Millisecond, "test multi deadline case") 37 | 38 | if err := dl.Run(workerTakes5ms); err != nil { 39 | t.Error(err) 40 | } 41 | 42 | err := dl.Run(cancelWork) 43 | 44 | t.Log("cancelWork error:", err) 45 | 46 | if err.Error() != "canceled job" { 47 | t.Error(err) 48 | } 49 | 50 | err = dl.Run(workerTakes20ms) 51 | 52 | if err != ErrTimedOut { 53 | t.Error(err) 54 | } 55 | } 56 | 57 | func TestDeadline(t *testing.T) { 58 | dl := New(1*time.Second, "one time deadline case worker") 59 | 60 | done := make(chan error) 61 | 62 | err := dl.Run(func(stopper chan error) error { 63 | fmt.Println("i am doing something here") 64 | time.Sleep(time.Second * 2) 65 | close(done) 66 | return nil 67 | }) 68 | if err != nil { 69 | t.Log(err) 70 | } 71 | 72 | if err != ErrTimedOut { 73 | t.Error(err) 74 | } 75 | <-done 76 | } 77 | -------------------------------------------------------------------------------- /stability/deadline/examples/example1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func task(ctx context.Context) { 10 | deadline, ok := ctx.Deadline() 11 | if ok { 12 | fmt.Println("Task deadline:", deadline) 13 | } 14 | 15 | select { 16 | case <-time.After(2 * time.Second): 17 | fmt.Println("Task completed successfully") 18 | case <-ctx.Done(): 19 | fmt.Println("Task canceled due to deadline exceeded") 20 | } 21 | } 22 | 23 | func main() { 24 | ctx := context.Background() 25 | ctx, cancel := context.WithDeadline(ctx, time.Now().Add(3*time.Second)) 26 | defer cancel() 27 | 28 | fmt.Println("Task start") 29 | task(ctx) 30 | fmt.Println("Task end") 31 | } 32 | -------------------------------------------------------------------------------- /stability/deadline/examples/example2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | // ErrTimedOut 是在截止时间过期时从 Run 返回的错误。 10 | var ErrTimedOut = errors.New("Timed out waiting for function to finish") 11 | 12 | // Deadline 实现了截止时间/超时恢复模式。 13 | type Deadline struct { 14 | timeout time.Duration 15 | } 16 | 17 | // New 使用给定的超时时间构造一个新的 Deadline。 18 | func New(timeout time.Duration) *Deadline { 19 | return &Deadline{ 20 | timeout: timeout, 21 | } 22 | } 23 | 24 | func (d *Deadline) Run(work func(<-chan struct{}) error) error { 25 | result := make(chan error) // 用于接收工作函数的结果 26 | stopper := make(chan struct{}) // 用于停止工作函数的信号 27 | 28 | go func() { 29 | value := work(stopper) // 调用工作函数 30 | select { 31 | case result <- value: // 将工作函数的结果发送到 result 通道 32 | case <-stopper: // 如果收到停止信号,则不发送结果 33 | } 34 | }() 35 | 36 | select { 37 | case ret := <-result: // 等待工作函数的结果 38 | return ret 39 | case <-time.After(d.timeout): // 如果超过截止时间 40 | close(stopper) // 关闭 stopper 通道,停止工作函数 41 | return ErrTimedOut // 返回超时错误 42 | } 43 | } 44 | 45 | func main() { 46 | dl := New(1 * time.Second) // 创建一个截止时间为 1 秒的 Deadline 47 | 48 | err := dl.Run(func(stopper <-chan struct{}) error { 49 | time.Sleep(2 * time.Second) // 模拟一个可能耗时的操作 50 | // 做一些可能耗时的操作 51 | // 检查 stopper 函数,如果超时则放弃 52 | fmt.Println("任务成功完成") 53 | return nil 54 | }) 55 | 56 | if err != nil { 57 | fmt.Println(err) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /stability/failfast/README.md: -------------------------------------------------------------------------------- 1 | ## 快速失败模式 2 | 3 | 快速失败模式(Fail-Fast Pattern)用于在系统出现问题时尽快失败并停止执行,以避免问题被传播并导致更严重的后果。该模式在软件开发中常用于快速定位和解决问题,提高系统的稳定性和可靠性。 4 | -------------------------------------------------------------------------------- /stability/failfast/failfast.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | func processInput(input string) error { 10 | if input == "" { 11 | return errors.New("Input cannot be empty") 12 | } 13 | 14 | // 假设这里有一些处理逻辑 15 | 16 | return nil 17 | } 18 | 19 | func main() { 20 | input := "" 21 | err := processInput(input) 22 | if err != nil { 23 | fmt.Println("Error:", err) 24 | os.Exit(1) 25 | } 26 | 27 | // 继续执行其他操作 28 | fmt.Println("Continue with other operations") 29 | } 30 | -------------------------------------------------------------------------------- /stability/handshaking/README.md: -------------------------------------------------------------------------------- 1 | ## 握手模式 2 | 3 | 握手模式(Handshaking Pattern)用于建立通信连接前进行双方协商和确认,确保双方能够彼此理解和支持相应的通信协议和数据格式。在网络编程和分布式系统中经常使用 Handshaking 模式,以确保通信的稳定性和有效性。 4 | -------------------------------------------------------------------------------- /stability/handshaking/handshaking.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func clientHandshake(ch chan string) { 9 | fmt.Println("Client: Sending handshake request") 10 | ch <- "Handshake Request" 11 | response := <-ch 12 | fmt.Println("Client: Received handshake response -", response) 13 | } 14 | 15 | func serverHandshake(ch chan string) { 16 | fmt.Println("Server: Waiting for handshake request") 17 | request := <-ch 18 | fmt.Println("Server: Received handshake request -", request) 19 | time.Sleep(2 * time.Second) // 模拟处理时间 20 | fmt.Println("Server: Sending handshake response") 21 | ch <- "Handshake Response" 22 | } 23 | 24 | func main() { 25 | ch := make(chan string) 26 | 27 | go serverHandshake(ch) 28 | go clientHandshake(ch) 29 | 30 | time.Sleep(3 * time.Second) // 等待握手完成 31 | } 32 | -------------------------------------------------------------------------------- /stability/ratelimiting/README.md: -------------------------------------------------------------------------------- 1 | ## 限流模式 2 | 3 | 限流模式(Rate Limiting Pattern)用于控制系统中某个服务、功能或资源的访问速率,防止过多的请求造成系统资源耗尽或服务不可用。在面对高并发请求或恶意攻击时,限流模式可以有效地控制流量,并保护系统免受过载的影响。 4 | -------------------------------------------------------------------------------- /stability/ratelimiting/rate_limiting.go: -------------------------------------------------------------------------------- 1 | package ratelimit 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func rateLimiting(requestQueue chan int, duration int64, allowedBurstCount int) { 9 | //根据允许的突发数量,创建 ch 10 | //只要该队列中有内容,就可以一直取出来,即便 ch 已经关闭 11 | burstyLimiter := make(chan time.Time, allowedBurstCount) 12 | 13 | //初始化允许突发的数量 14 | for i := 0; i < allowedBurstCount; i++ { 15 | burstyLimiter <- time.Now() 16 | } 17 | 18 | //控制请求频率的计时器 19 | go func() { 20 | for t := range time.Tick(time.Duration(duration) * time.Millisecond) { 21 | burstyLimiter <- t 22 | } 23 | }() 24 | 25 | for req := range requestQueue { 26 | <-burstyLimiter //突发控制器是限流的关键 27 | fmt.Println("request", req, time.Now()) 28 | } 29 | } 30 | 31 | // Another rate limiting example in simple way. 32 | func simpleRateLimiting(duration int64, requestQueueSize int) { 33 | requests := make(chan int, requestQueueSize) 34 | for i := 1; i <= requestQueueSize; i++ { 35 | requests <- i 36 | } 37 | close(requests) 38 | 39 | limiter := time.Tick(time.Duration(duration) * time.Millisecond) 40 | 41 | for req := range requests { 42 | <-limiter 43 | fmt.Println("request", req, time.Now()) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /stability/ratelimiting/rate_limiting_test.go: -------------------------------------------------------------------------------- 1 | package ratelimit 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var ( 8 | requestQueueSize = 10 9 | ) 10 | 11 | func TestRateLimiting(t *testing.T) { 12 | //请求队列 13 | burstyRequests := make(chan int, requestQueueSize) 14 | 15 | for i := 1; i <= requestQueueSize; i++ { 16 | burstyRequests <- i 17 | } 18 | close(burstyRequests) 19 | 20 | //对请求进行限流 21 | 22 | //200ms允许一次请求,最多同时3个突发 23 | rateLimiting(burstyRequests, 200, 3) 24 | } 25 | -------------------------------------------------------------------------------- /stability/retrier/README.md: -------------------------------------------------------------------------------- 1 | ## 重试模式 2 | 3 | 重试模式(Retry Pattern)用于处理系统请求或操作失败的情况,通过在一定时间间隔内多次尝试重复执行失败的操作,以增加操作成功的可能性。重试模式能够提高系统的可靠性和稳定性,尤其在面对网络不稳定或服务故障等情况下特别有用。 4 | -------------------------------------------------------------------------------- /stability/retrier/example/backoffs.go: -------------------------------------------------------------------------------- 1 | package retrier 2 | 3 | import "time" 4 | 5 | // ConstantBackoff generates a simple back-off strategy of retrying 'n' times, and waiting 'amount' time after each one. 6 | func ConstantBackoff(n int, amount time.Duration) []time.Duration { 7 | ret := make([]time.Duration, n) 8 | for i := range ret { 9 | ret[i] = amount 10 | } 11 | return ret 12 | } 13 | 14 | // ExponentialBackoff generates a simple back-off strategy of retrying 'n' times, and doubling the amount of 15 | // time waited after each one. 16 | func ExponentialBackoff(n int, initialAmount time.Duration) []time.Duration { 17 | ret := make([]time.Duration, n) 18 | next := initialAmount 19 | for i := range ret { 20 | ret[i] = next 21 | next *= 2 22 | } 23 | return ret 24 | } 25 | -------------------------------------------------------------------------------- /stability/retrier/example/backoffs_test.go: -------------------------------------------------------------------------------- 1 | package retrier 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestConstantBackoff(t *testing.T) { 9 | b := ConstantBackoff(1, 10*time.Millisecond) 10 | if len(b) != 1 { 11 | t.Error("incorrect length") 12 | } 13 | for i := range b { 14 | if b[i] != 10*time.Millisecond { 15 | t.Error("incorrect value at", i) 16 | } 17 | } 18 | 19 | b = ConstantBackoff(10, 250*time.Hour) 20 | if len(b) != 10 { 21 | t.Error("incorrect length") 22 | } 23 | for i := range b { 24 | if b[i] != 250*time.Hour { 25 | t.Error("incorrect value at", i) 26 | } 27 | } 28 | } 29 | 30 | func TestExponentialBackoff(t *testing.T) { 31 | b := ExponentialBackoff(1, 10*time.Millisecond) 32 | if len(b) != 1 { 33 | t.Error("incorrect length") 34 | } 35 | if b[0] != 10*time.Millisecond { 36 | t.Error("incorrect value") 37 | } 38 | 39 | b = ExponentialBackoff(4, 1*time.Minute) 40 | if len(b) != 4 { 41 | t.Error("incorrect length") 42 | } 43 | if b[0] != 1*time.Minute { 44 | t.Error("incorrect value") 45 | } 46 | if b[1] != 2*time.Minute { 47 | t.Error("incorrect value") 48 | } 49 | if b[2] != 4*time.Minute { 50 | t.Error("incorrect value") 51 | } 52 | if b[3] != 8*time.Minute { 53 | t.Error("incorrect value") 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /stability/retrier/example/classifier.go: -------------------------------------------------------------------------------- 1 | package retrier 2 | 3 | // Action is the type returned by a Classifier to indicate how the Retrier should proceed. 4 | type Action int 5 | 6 | const ( 7 | Succeed Action = iota // Succeed indicates the Retrier should treat this value as a success. 8 | Fail // Fail indicates the Retrier should treat this value as a hard failure and not retry. 9 | Retry // Retry indicates the Retrier should treat this value as a soft failure and retry. 10 | ) 11 | 12 | // Classifier is the interface implemented by anything that can classify Errors for a Retrier. 13 | type Classifier interface { 14 | Classify(error) Action 15 | } 16 | 17 | // DefaultClassifier classifies errors in the simplest way possible. If 18 | // the error is nil, it returns Succeed, otherwise it returns Retry. 19 | type DefaultClassifier struct{} 20 | 21 | // Classify implements the Classifier interface. 22 | func (c DefaultClassifier) Classify(err error) Action { 23 | if err == nil { 24 | return Succeed 25 | } 26 | 27 | return Retry 28 | } 29 | 30 | // WhitelistClassifier classifies errors based on a whitelist. If the error is nil, it 31 | // returns Succeed; if the error is in the whitelist, it returns Retry; otherwise, it returns Fail. 32 | type WhitelistClassifier []error 33 | 34 | // Classify implements the Classifier interface. 35 | func (list WhitelistClassifier) Classify(err error) Action { 36 | if err == nil { 37 | return Succeed 38 | } 39 | 40 | for _, pass := range list { 41 | if err == pass { 42 | return Retry 43 | } 44 | } 45 | 46 | return Fail 47 | } 48 | 49 | // BlacklistClassifier classifies errors based on a blacklist. If the error is nil, it 50 | // returns Succeed; if the error is in the blacklist, it returns Fail; otherwise, it returns Retry. 51 | type BlacklistClassifier []error 52 | 53 | // Classify implements the Classifier interface. 54 | func (list BlacklistClassifier) Classify(err error) Action { 55 | if err == nil { 56 | return Succeed 57 | } 58 | 59 | for _, pass := range list { 60 | if err == pass { 61 | return Fail 62 | } 63 | } 64 | 65 | return Retry 66 | } 67 | -------------------------------------------------------------------------------- /stability/retrier/example/classifier_test.go: -------------------------------------------------------------------------------- 1 | package retrier 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestDefaultClassifier(t *testing.T) { 8 | c := DefaultClassifier{} 9 | 10 | if c.Classify(nil) != Succeed { 11 | t.Error("default misclassified nil") 12 | } 13 | 14 | if c.Classify(errFoo) != Retry { 15 | t.Error("default misclassified foo") 16 | } 17 | if c.Classify(errBar) != Retry { 18 | t.Error("default misclassified bar") 19 | } 20 | if c.Classify(errBaz) != Retry { 21 | t.Error("default misclassified baz") 22 | } 23 | } 24 | 25 | func TestWhitelistClassifier(t *testing.T) { 26 | c := WhitelistClassifier{errFoo, errBar} 27 | 28 | if c.Classify(nil) != Succeed { 29 | t.Error("whitelist misclassified nil") 30 | } 31 | 32 | if c.Classify(errFoo) != Retry { 33 | t.Error("whitelist misclassified foo") 34 | } 35 | if c.Classify(errBar) != Retry { 36 | t.Error("whitelist misclassified bar") 37 | } 38 | if c.Classify(errBaz) != Fail { 39 | t.Error("whitelist misclassified baz") 40 | } 41 | } 42 | 43 | func TestBlacklistClassifier(t *testing.T) { 44 | c := BlacklistClassifier{errBar} 45 | 46 | if c.Classify(nil) != Succeed { 47 | t.Error("blacklist misclassified nil") 48 | } 49 | 50 | if c.Classify(errFoo) != Retry { 51 | t.Error("blacklist misclassified foo") 52 | } 53 | if c.Classify(errBar) != Fail { 54 | t.Error("blacklist misclassified bar") 55 | } 56 | if c.Classify(errBaz) != Retry { 57 | t.Error("blacklist misclassified baz") 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /stability/retrier/example/retrier.go: -------------------------------------------------------------------------------- 1 | // Package retrier implements the "retriable" resiliency pattern for Go. 2 | package retrier 3 | 4 | import ( 5 | "context" 6 | "math/rand" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | // Retrier implements the "retriable" resiliency pattern, abstracting out the process of retrying a failed action 12 | // a certain number of times with an optional back-off between each retry. 13 | type Retrier struct { 14 | backoff []time.Duration 15 | class Classifier 16 | jitter float64 17 | rand *rand.Rand 18 | randMu sync.Mutex 19 | } 20 | 21 | // New constructs a Retrier with the given backoff pattern and classifier. The length of the backoff pattern 22 | // indicates how many times an action will be retried, and the value at each index indicates the amount of time 23 | // waited before each subsequent retry. The classifier is used to determine which errors should be retried and 24 | // which should cause the retrier to fail fast. The DefaultClassifier is used if nil is passed. 25 | func New(backoff []time.Duration, class Classifier) *Retrier { 26 | if class == nil { 27 | class = DefaultClassifier{} 28 | } 29 | 30 | return &Retrier{ 31 | backoff: backoff, 32 | class: class, 33 | rand: rand.New(rand.NewSource(time.Now().UnixNano())), 34 | } 35 | } 36 | 37 | // Run executes the given work function by executing RunCtx without context.Context. 38 | func (r *Retrier) Run(work func() error) error { 39 | return r.RunCtx(context.Background(), func(ctx context.Context) error { 40 | // never use ctx 41 | return work() 42 | }) 43 | } 44 | 45 | // RunCtx executes the given work function, then classifies its return value based on the classifier used 46 | // to construct the Retrier. If the result is Succeed or Fail, the return value of the work function is 47 | // returned to the caller. If the result is Retry, then Run sleeps according to the its backoff policy 48 | // before retrying. If the total number of retries is exceeded then the return value of the work function 49 | // is returned to the caller regardless. 50 | func (r *Retrier) RunCtx(ctx context.Context, work func(ctx context.Context) error) error { 51 | retries := 0 52 | for { 53 | ret := work(ctx) 54 | 55 | switch r.class.Classify(ret) { 56 | case Succeed, Fail: 57 | return ret 58 | case Retry: 59 | if retries >= len(r.backoff) { 60 | return ret 61 | } 62 | 63 | timeout := time.After(r.calcSleep(retries)) 64 | if err := r.sleep(ctx, timeout); err != nil { 65 | return err 66 | } 67 | 68 | retries++ 69 | } 70 | } 71 | } 72 | 73 | func (r *Retrier) sleep(ctx context.Context, t <-chan time.Time) error { 74 | select { 75 | case <-t: 76 | return nil 77 | case <-ctx.Done(): 78 | return ctx.Err() 79 | } 80 | } 81 | 82 | func (r *Retrier) calcSleep(i int) time.Duration { 83 | // lock unsafe rand prog 84 | r.randMu.Lock() 85 | defer r.randMu.Unlock() 86 | // take a random float in the range (-r.jitter, +r.jitter) and multiply it by the base amount 87 | return r.backoff[i] + time.Duration(((r.rand.Float64()*2)-1)*r.jitter*float64(r.backoff[i])) 88 | } 89 | 90 | // SetJitter sets the amount of jitter on each back-off to a factor between 0.0 and 1.0 (values outside this range 91 | // are silently ignored). When a retry occurs, the back-off is adjusted by a random amount up to this value. 92 | func (r *Retrier) SetJitter(jit float64) { 93 | if jit < 0 || jit > 1 { 94 | return 95 | } 96 | r.jitter = jit 97 | } 98 | -------------------------------------------------------------------------------- /stability/retrier/example/retrier_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: https://github.com/crazybber 3 | * @Author: Edward 4 | * @Date: 2020-05-11 17:43:55 5 | * @Last Modified by: Edward 6 | * @Last Modified time: 2020-05-11 17:43:55 7 | */ 8 | 9 | package retrier 10 | 11 | import ( 12 | "context" 13 | "errors" 14 | "testing" 15 | "time" 16 | ) 17 | 18 | var ( 19 | i int 20 | errFoo = errors.New("work cancel") 21 | errBar = errors.New("work cancel 2") 22 | errBaz = errors.New("work cancel 3") 23 | ) 24 | 25 | func genWork(returns []error) func() error { 26 | i = 0 27 | return func() error { 28 | i++ 29 | if i > len(returns) { 30 | return nil 31 | } 32 | return returns[i-1] 33 | } 34 | } 35 | 36 | func genWorkWithCtx() func(ctx context.Context) error { 37 | i = 0 38 | return func(ctx context.Context) error { 39 | select { 40 | case <-ctx.Done(): 41 | return errFoo 42 | default: 43 | i++ 44 | } 45 | return nil 46 | } 47 | } 48 | 49 | func TestRetrier(t *testing.T) { 50 | r := New([]time.Duration{0, 10 * time.Millisecond}, WhitelistClassifier{errFoo}) 51 | 52 | err := r.Run(genWork([]error{errFoo, errFoo})) 53 | if err != nil { 54 | t.Error(err) 55 | } 56 | if i != 3 { 57 | t.Error("run wrong number of times") 58 | } 59 | 60 | err = r.Run(genWork([]error{errFoo, errBar})) 61 | if err != errBar { 62 | t.Error(err) 63 | } 64 | if i != 2 { 65 | t.Error("run wrong number of times") 66 | } 67 | 68 | err = r.Run(genWork([]error{errBar, errBaz})) 69 | if err != errBar { 70 | t.Error(err) 71 | } 72 | if i != 1 { 73 | t.Error("run wrong number of times") 74 | } 75 | } 76 | 77 | func TestRetrierCtx(t *testing.T) { 78 | ctx, cancel := context.WithCancel(context.Background()) 79 | 80 | r := New([]time.Duration{0, 10 * time.Millisecond}, WhitelistClassifier{}) 81 | 82 | err := r.RunCtx(ctx, genWorkWithCtx()) 83 | if err != nil { 84 | t.Error(err) 85 | } 86 | if i != 1 { 87 | t.Error("run wrong number of times") 88 | } 89 | 90 | cancel() 91 | 92 | err = r.RunCtx(ctx, genWorkWithCtx()) 93 | if err != errFoo { 94 | t.Error("context must be cancelled") 95 | } 96 | if i != 0 { 97 | t.Error("run wrong number of times") 98 | } 99 | } 100 | 101 | func TestRetrierNone(t *testing.T) { 102 | r := New(nil, nil) 103 | 104 | i = 0 105 | err := r.Run(func() error { 106 | i++ 107 | return errFoo 108 | }) 109 | if err != errFoo { 110 | t.Error(err) 111 | } 112 | if i != 1 { 113 | t.Error("run wrong number of times") 114 | } 115 | 116 | i = 0 117 | err = r.Run(func() error { 118 | i++ 119 | return nil 120 | }) 121 | if err != nil { 122 | t.Error(err) 123 | } 124 | if i != 1 { 125 | t.Error("run wrong number of times") 126 | } 127 | } 128 | 129 | func TestRetrierJitter(t *testing.T) { 130 | r := New([]time.Duration{0, 10 * time.Millisecond, 4 * time.Hour}, nil) 131 | 132 | if r.calcSleep(0) != 0 { 133 | t.Error("Incorrect sleep calculated") 134 | } 135 | if r.calcSleep(1) != 10*time.Millisecond { 136 | t.Error("Incorrect sleep calculated") 137 | } 138 | if r.calcSleep(2) != 4*time.Hour { 139 | t.Error("Incorrect sleep calculated") 140 | } 141 | 142 | r.SetJitter(0.25) 143 | for i := 0; i < 20; i++ { 144 | if r.calcSleep(0) != 0 { 145 | t.Error("Incorrect sleep calculated") 146 | } 147 | 148 | slp := r.calcSleep(1) 149 | if slp < 7500*time.Microsecond || slp > 12500*time.Microsecond { 150 | t.Error("Incorrect sleep calculated") 151 | } 152 | 153 | slp = r.calcSleep(2) 154 | if slp < 3*time.Hour || slp > 5*time.Hour { 155 | t.Error("Incorrect sleep calculated") 156 | } 157 | } 158 | 159 | r.SetJitter(-1) 160 | if r.jitter != 0.25 { 161 | t.Error("Invalid jitter value accepted") 162 | } 163 | 164 | r.SetJitter(2) 165 | if r.jitter != 0.25 { 166 | t.Error("Invalid jitter value accepted") 167 | } 168 | } 169 | 170 | func TestRetrierThreadSafety(t *testing.T) { 171 | r := New([]time.Duration{0}, nil) 172 | for i := 0; i < 2; i++ { 173 | go func() { 174 | r.Run(func() error { 175 | return errors.New("error") 176 | }) 177 | }() 178 | } 179 | } 180 | 181 | func ExampleRetrier() { 182 | r := New(ConstantBackoff(3, 100*time.Millisecond), nil) 183 | 184 | err := r.Run(func() error { 185 | // do some work 186 | return nil 187 | }) 188 | 189 | if err != nil { 190 | // handle the case where the work failed three times 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /stability/retrier/retrier.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func retryOperation(operation func() error, maxRetries int, interval time.Duration) error { 9 | var err error 10 | for i := 0; i < maxRetries; i++ { 11 | err = operation() 12 | if err == nil { 13 | return nil // 操作成功,直接返回 14 | } 15 | fmt.Printf("Operation failed: %s. Retrying...\n", err) 16 | time.Sleep(interval) 17 | } 18 | return err 19 | } 20 | 21 | func main() { 22 | maxRetries := 3 23 | interval := 2 * time.Second 24 | 25 | err := retryOperation(func() error { 26 | fmt.Println("Performing operation...") 27 | return performOperation() // 假设 performOperation 是一个可能失败的操作 28 | }, maxRetries, interval) 29 | 30 | if err != nil { 31 | fmt.Printf("Operation failed after %d retries: %s\n", maxRetries, err) 32 | } else { 33 | fmt.Println("Operation successful!") 34 | } 35 | } 36 | 37 | func performOperation() error { 38 | // 模拟一个可能失败的操作 39 | if time.Now().Unix()%2 == 0 { 40 | return fmt.Errorf("Random error occurred") 41 | } 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /stability/steadystate/README.md: -------------------------------------------------------------------------------- 1 | ## 稳态模式 2 | 3 | 稳态模式(Steady-State Pattern)可以理解为系统在达到稳定状态后的处理模式。在这种模式下,系统在稳态期间能够持续稳定地处理请求或任务,保持良好的性能和可靠性。Steady-State 模式注重系统的持续稳定运行,确保系统在高负载和压力下依然能够正常工作。 4 | -------------------------------------------------------------------------------- /stability/steadystate/steadystate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func processTask(id int) { 9 | fmt.Printf("Processing task %d\n", id) 10 | time.Sleep(1 * time.Second) // 模拟任务处理时间 11 | } 12 | 13 | func main() { 14 | taskCount := 5 15 | taskInterval := 2 * time.Second 16 | 17 | fmt.Println("System is in Steady-State") 18 | 19 | for i := 1; i <= taskCount; i++ { 20 | go processTask(i) 21 | time.Sleep(taskInterval) 22 | } 23 | 24 | time.Sleep(taskInterval) 25 | fmt.Println("All tasks processed successfully") 26 | } 27 | -------------------------------------------------------------------------------- /structural/adapter/README.md: -------------------------------------------------------------------------------- 1 | ## 外观模式 2 | 3 | 外观模式(Facade Pattern)又称门面模式,旨在为复杂系统提供一个简单统一的接口,以减少系统之间的相互依赖和简化对外部系统的访问。外观模式通过封装一组复杂的子系统,隐藏其复杂性并提供一个简化的接口供客户端使用。 4 | -------------------------------------------------------------------------------- /structural/adapter/adapter.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import "fmt" 4 | 5 | // IPlug 插头 6 | type IPlug interface { 7 | GetPin() int 8 | } 9 | 10 | // TwoPinPlugin 造一个两针的插头 11 | type TwoPinPlugin struct { 12 | } 13 | 14 | // GetPin 获取插头针数 15 | func (t *TwoPinPlugin) GetPin() int { 16 | return 2 17 | } 18 | 19 | // IPowerSocket 电源插座 20 | type IPowerSocket interface { 21 | PlugCharging(p IPlug) 22 | } 23 | 24 | // IThreePinPowerSocket 三孔插座 25 | type IThreePinPowerSocket interface { 26 | ThreePinCharging(p IPlug) 27 | } 28 | 29 | // ThreePinPowerSocket 是被适配的目标类 30 | type ThreePinPowerSocket struct{} 31 | 32 | // ThreePinCharging 只能为三针的插头通电 33 | func (*ThreePinPowerSocket) ThreePinCharging(p IPlug) { 34 | if p.GetPin() != 3 { 35 | fmt.Println("i can not charge for this type") 36 | return 37 | } 38 | fmt.Println("charging for three pin plug") 39 | } 40 | 41 | // NewPowerAdapter 生产一个新的电源适配器 42 | func NewPowerAdapter(threePinPowerSocket IThreePinPowerSocket) IPowerSocket { 43 | return &PowerAdapter{IThreePinPowerSocket(threePinPowerSocket), 0} 44 | } 45 | 46 | // PowerAdapter 是能充电的关键电源转换器 47 | type PowerAdapter struct { 48 | IThreePinPowerSocket 49 | pin int 50 | } 51 | 52 | // GetPin Adapter 的兼容能力 53 | func (p *PowerAdapter) GetPin() int { 54 | return p.pin 55 | } 56 | 57 | // PlugCharging 在PowerAdapter上进行实现 58 | func (p *PowerAdapter) PlugCharging(ip IPlug) { 59 | if ip.GetPin() == 2 { 60 | p.pin = 3 61 | p.ThreePinCharging(p) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /structural/adapter/adapter_test.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | func ExampleAdapter() { 4 | plug := &TwoPinPlugin{} 5 | 6 | threePinSocket := ThreePinPowerSocket{} 7 | 8 | //三孔插头是不能为两针插头充电的,可以试试看 9 | threePinSocket.ThreePinCharging(plug) 10 | 11 | //只好加一个电源适配器 12 | powersocket := NewPowerAdapter(&threePinSocket) 13 | 14 | //再试试能不能充电 15 | powersocket.PlugCharging(plug) 16 | 17 | // Output: 18 | // i can not charge for this type 19 | // charging for three pin plug 20 | } 21 | -------------------------------------------------------------------------------- /structural/bridge/README.md: -------------------------------------------------------------------------------- 1 | ## 桥接模式 2 | 3 | 桥接模式(Bridge Pattern)用于将抽象部分与实现部分分离,使它们可以独立变化而互不影响。桥接模式通过对象间的组合关系,取代继承关系,实现系统中的多层次复杂功能。 4 | -------------------------------------------------------------------------------- /structural/bridge/bridge.go: -------------------------------------------------------------------------------- 1 | package bridge 2 | 3 | import "fmt" 4 | 5 | // Applications 家电接口定义了家用电器的基本行为 6 | type Applications interface { 7 | Run() // Run 方法表示家电运行的行为 8 | Name() string // Name 方法返回家电的名称 9 | } 10 | 11 | // Bulb 灯泡类实现了家电接口 12 | type Bulb struct { 13 | } 14 | 15 | func (b *Bulb) Name() string { 16 | return "Bulb" 17 | } 18 | 19 | func (b *Bulb) Run() { 20 | fmt.Printf("灯泡 %v 亮了!\n", b.Name()) 21 | } 22 | 23 | // Fan 电扇类实现了家电接口 24 | type Fan struct { 25 | } 26 | 27 | func (f *Fan) Name() string { 28 | return "Fan" 29 | } 30 | 31 | func (f *Fan) Run() { 32 | fmt.Printf("电扇 %v 转动\n", f.Name()) 33 | } 34 | 35 | // Switch 开关接口定义了开关的基本行为 36 | type Switch interface { 37 | TurnOn() // TurnOn 方法表示打开开关 38 | TurnOff() // TurnOff 方法表示关闭开关 39 | } 40 | 41 | // CircleSwitch 圆形开关类实现了开关接口 42 | type CircleSwitch struct { 43 | application Applications // 关联的家电 44 | } 45 | 46 | func NewCircleSwitch(application Applications) *CircleSwitch { 47 | return &CircleSwitch{application: application} 48 | } 49 | 50 | func (c *CircleSwitch) TurnOn() { 51 | fmt.Printf("打开圆形开关,打开 %s,开始运行 ", c.application.Name()) 52 | c.application.Run() 53 | } 54 | 55 | func (c *CircleSwitch) TurnOff() { 56 | fmt.Printf("关闭圆形开关,关闭 %s\n", c.application.Name()) 57 | } 58 | 59 | // SquareSwitch 方形开关类实现了开关接口 60 | type SquareSwitch struct { 61 | application Applications // 关联的家电 62 | } 63 | 64 | func NewSquareSwitch(application Applications) *SquareSwitch { 65 | return &SquareSwitch{application: application} 66 | } 67 | 68 | func (c *SquareSwitch) TurnOn() { 69 | fmt.Printf("打开方形开关,打开 %s,开始运行 ", c.application.Name()) 70 | c.application.Run() 71 | } 72 | 73 | func (c *SquareSwitch) TurnOff() { 74 | fmt.Printf("关闭方形开关,关闭 %s\n", c.application.Name()) 75 | } 76 | -------------------------------------------------------------------------------- /structural/bridge/bridge_test.go: -------------------------------------------------------------------------------- 1 | package bridge 2 | 3 | func ExampleBridge() { 4 | // 使用圆形开关控制灯泡 5 | cs := NewCircleSwitch(&Bulb{}) 6 | cs.TurnOn() 7 | cs.TurnOff() 8 | 9 | // 使用圆形开关控制电扇 10 | cs = NewCircleSwitch(&Fan{}) 11 | cs.TurnOn() 12 | cs.TurnOff() 13 | 14 | // 使用方形开关控制灯泡 15 | ss := NewSquareSwitch(&Bulb{}) 16 | ss.TurnOn() 17 | ss.TurnOff() 18 | 19 | // 使用方形开关控制电扇 20 | ss = NewSquareSwitch(&Fan{}) 21 | ss.TurnOn() 22 | ss.TurnOff() 23 | // Output: 24 | // 打开圆形开关,打开 Bulb,开始运行 灯泡 Bulb 亮了! 25 | // 关闭圆形开关,关闭 Bulb 26 | // 打开圆形开关,打开 Fan,开始运行 电扇 Fan 转动 27 | // 关闭圆形开关,关闭 Fan 28 | // 打开方形开关,打开 Bulb,开始运行 灯泡 Bulb 亮了! 29 | // 关闭方形开关,关闭 Bulb 30 | // 打开方形开关,打开 Fan,开始运行 电扇 Fan 转动 31 | // 关闭方形开关,关闭 Fan 32 | } 33 | -------------------------------------------------------------------------------- /structural/composite/README.md: -------------------------------------------------------------------------------- 1 | ## 组合模式 2 | 3 | 组合模式(Composite Pattern)主要可以应用在带有树状关系的业务场景。比如一个文件系统包含了很多的文件夹,每一个文件夹下面又包含了许多的文件,彼此之间的关系组成了一颗树状的结构。我们可以将这颗树理解成一个大的容器,容器里面包含很多的成员对象,这些成员对象即可是容器对象【非叶子结点】也可以是叶子对象【叶子节点】。但是由于容器对象和叶子对象在功能上面的区别,使得我们在使用的过程中必须要区分容器对象和叶子对象,但是这样就会给客户带来不必要的麻烦,作为客户,它始终希望能够一致的对待容器对象和叶子对象。 4 | -------------------------------------------------------------------------------- /structural/composite/composite.go: -------------------------------------------------------------------------------- 1 | package composite 2 | 3 | import "fmt" 4 | 5 | // INode 是节点接口,定义了节点操作的基本方法 6 | type INode interface { 7 | Add(child INode) // 添加子节点 8 | Tree(space int) // 显示节点树状结构 9 | } 10 | 11 | // Node 是抽象节点,包含节点公共属性 12 | type Node struct { 13 | name string 14 | } 15 | 16 | // NewNode 创建一个新的抽象节点 17 | func NewNode(name string) *Node { 18 | return &Node{name: name} 19 | } 20 | 21 | // Add 实现了节点接口的添加方法,抽象节点默认不添加子节点 22 | func (n *Node) Add(child INode) {} 23 | 24 | // Tree 实现了节点接口的展示方法,用于显示节点名称 25 | func (n *Node) Tree(space int) { 26 | for i := 0; i < space; i++ { 27 | fmt.Print(" ") 28 | } 29 | fmt.Println(n.name) 30 | } 31 | 32 | // Folder 是目录类,实现了节点接口 33 | type Folder struct { 34 | Node // 继承抽象节点 35 | nodes []INode // 子节点列表 36 | } 37 | 38 | // NewFolder 创建一个新的目录 39 | func NewFolder(name string) *Folder { 40 | return &Folder{ 41 | Node: Node{name: name}, 42 | } 43 | } 44 | 45 | // Add 实现了节点接口的添加方法,在目录中添加子节点 46 | func (f *Folder) Add(children INode) { 47 | if len(f.nodes) == 0 { 48 | f.nodes = make([]INode, 0) 49 | } 50 | f.nodes = append(f.nodes, children) 51 | } 52 | 53 | // Tree 实现了节点接口的展示方法,显示目录下的子节点 54 | func (f *Folder) Tree(space int) { 55 | f.Node.Tree(space) 56 | space++ 57 | 58 | for _, node := range f.nodes { 59 | node.Tree(space) 60 | } 61 | } 62 | 63 | // File 是文件类,实现了节点接口 64 | type File struct { 65 | Node // 继承抽象节点 66 | } 67 | 68 | // NewFile 创建一个新的文件 69 | func NewFile(name string) *File { 70 | return &File{ 71 | Node: Node{name: name}, 72 | } 73 | } 74 | 75 | // Add 实现了节点接口的添加方法,文件类不允许添加子节点 76 | func (f *File) Add(child INode) { 77 | fmt.Println("不允许添加子节点") 78 | } 79 | 80 | // Tree 实现了节点接口的展示方法,显示文件节点 81 | func (f *File) Tree(space int) { 82 | f.Node.Tree(space) 83 | } 84 | -------------------------------------------------------------------------------- /structural/composite/composite_test.go: -------------------------------------------------------------------------------- 1 | package composite 2 | 3 | func ExampleComposite() { 4 | driveD := NewFolder("D盘") 5 | 6 | // 创建文档目录及文件 7 | docDir := NewFolder("文档") 8 | docDir.Add(NewFile("简历.doc")) 9 | docDir.Add(NewFile("项目介绍.ppt")) 10 | driveD.Add(docDir) 11 | 12 | // 创建音乐目录及文件 13 | musicDir := NewFolder("音乐") 14 | 15 | jayDir := NewFolder("周杰伦") 16 | jayDir.Add(NewFile("发如雪.mp3")) 17 | jayDir.Add(NewFile("青花瓷.mp3")) 18 | 19 | easonDir := NewFolder("陈奕迅") 20 | easonDir.Add(NewFile("十年.mp3")) 21 | easonDir.Add(NewFile("富士山下.mp3")) 22 | 23 | musicDir.Add(jayDir) 24 | musicDir.Add(easonDir) 25 | 26 | driveD.Add(musicDir) 27 | 28 | driveD.Tree(0) // 显示整个节点树 29 | // Output: 30 | // D盘 31 | // 文档 32 | // 简历.doc 33 | // 项目介绍.ppt 34 | // 音乐 35 | // 周杰伦 36 | // 发如雪.mp3 37 | // 青花瓷.mp3 38 | // 陈奕迅 39 | // 十年.mp3 40 | // 富士山下.mp3 41 | } 42 | -------------------------------------------------------------------------------- /structural/decorator/README.md: -------------------------------------------------------------------------------- 1 | ## 装饰器模式 2 | 3 | 装饰器模式(Decorator Pattern)可以将不同功能的单个模块规划至不同的装饰器类中,各装饰器类独立自主,各司其职。客户端可以根据自己的需求自由搭配各种装饰器,每加一层装饰就会有新的特性体现出来,巧妙的设计让功能模块层层叠加,装饰之上套装饰,最终使原始对象的特性动态地得到增强。 4 | -------------------------------------------------------------------------------- /structural/decorator/decorator.go: -------------------------------------------------------------------------------- 1 | package decorator 2 | 3 | import "fmt" 4 | 5 | // Showable 是展示行为的接口 6 | type Showable interface { 7 | Show() // 展示 8 | } 9 | 10 | // Girl 表示女生类,实现了 Showable 接口 11 | type Girl struct{} 12 | 13 | // NewGirl 创建一个新的女生实例 14 | func NewGirl() *Girl { 15 | return &Girl{} 16 | } 17 | 18 | // Show 展示女生的素颜 19 | func (g *Girl) Show() { 20 | fmt.Print("女生的素颜") 21 | } 22 | 23 | // Decorator 是装饰器的基类 24 | type Decorator struct { 25 | showable Showable // 包含 Showable 接口的字段 26 | } 27 | 28 | // NewDecorator 创建一个新的装饰器 29 | func NewDecorator(showable Showable) *Decorator { 30 | return &Decorator{showable: showable} 31 | } 32 | 33 | // Show 展示装饰器的行为 34 | func (d *Decorator) Show() { 35 | d.showable.Show() 36 | } 37 | 38 | // FoundationMakeup 表示粉底装饰器 39 | type FoundationMakeup struct { 40 | Decorator // 继承自 Decorator 基类 41 | } 42 | 43 | // NewFoundationMakeup 创建一个新的粉底装饰器 44 | func NewFoundationMakeup(showable Showable) *FoundationMakeup { 45 | return &FoundationMakeup{Decorator: Decorator{showable: showable}} 46 | } 47 | 48 | // Show 展示打粉底的行为 49 | func (f *FoundationMakeup) Show() { 50 | fmt.Print("打粉底【") 51 | f.Decorator.Show() 52 | fmt.Print("】") 53 | } 54 | 55 | // Lipstick 表示口红装饰器 56 | type Lipstick struct { 57 | Decorator // 继承自 Decorator 基类 58 | } 59 | 60 | // NewLipstick 创建一个新的口红装饰器 61 | func NewLipstick(showable Showable) *Lipstick { 62 | return &Lipstick{Decorator: Decorator{showable: showable}} 63 | } 64 | 65 | // Show 展示涂口红的行为 66 | func (l *Lipstick) Show() { 67 | fmt.Print("涂口红【") 68 | l.Decorator.Show() 69 | fmt.Print("】") 70 | } 71 | -------------------------------------------------------------------------------- /structural/decorator/decorator_test.go: -------------------------------------------------------------------------------- 1 | package decorator 2 | 3 | import "fmt" 4 | 5 | func ExampleDecorator() { 6 | // 创建一个经过口红和粉底装饰的女生对象 7 | decoratedGirl := NewLipstick(NewFoundationMakeup(NewGirl())) 8 | decoratedGirl.Show() // 展示女生经过装饰后的样子 9 | fmt.Println() 10 | // Output: 11 | // 涂口红【打粉底【女生的素颜】】 12 | } 13 | -------------------------------------------------------------------------------- /structural/facade/README.md: -------------------------------------------------------------------------------- 1 | ## 外观模式 2 | 3 | 外观模式(Facade Pattern)又称门面模式,旨在为复杂系统提供一个简单统一的接口,以减少系统之间的相互依赖和简化对外部系统的访问。外观模式通过封装一组复杂的子系统,隐藏其复杂性并提供一个简化的接口供客户端使用。 4 | -------------------------------------------------------------------------------- /structural/facade/facade.go: -------------------------------------------------------------------------------- 1 | package facade 2 | 3 | import "fmt" 4 | 5 | // VegVendor 蔬菜供应商 6 | type VegVendor struct{} 7 | 8 | func (v *VegVendor) purchase() { 9 | fmt.Println("供应蔬菜") 10 | } 11 | 12 | // Chef 厨师 13 | type Chef struct{} 14 | 15 | func (c *Chef) Cook() { 16 | fmt.Println("下厨烹饪") 17 | } 18 | 19 | // Waiter 服务员 20 | type Waiter struct{} 21 | 22 | func (h *Waiter) Service() { 23 | fmt.Println("开始为用户服务") 24 | } 25 | 26 | // Cleaner 清洁工 27 | type Cleaner struct{} 28 | 29 | func (c *Cleaner) Clean() { 30 | fmt.Println("开始清洁卫生") 31 | } 32 | 33 | // Facade 外观结构体 34 | type Facade struct { 35 | vendor *VegVendor 36 | chef *Chef 37 | waiter *Waiter 38 | cleaner *Cleaner 39 | } 40 | 41 | // NewFacade 创建一个新的外观对象 42 | func NewFacade() *Facade { 43 | facade := &Facade{} 44 | facade.cleaner = &Cleaner{} 45 | facade.chef = &Chef{} 46 | facade.waiter = &Waiter{} 47 | facade.cleaner = &Cleaner{} 48 | 49 | return facade 50 | } 51 | 52 | // Order 开始处理订单流程 53 | func (f *Facade) Order() { 54 | // 服务员接待入座 55 | f.waiter.Service() 56 | // 厨师开始烹饪 57 | f.chef.Cook() 58 | // 上菜 59 | f.waiter.Service() 60 | // 收拾桌子洗碗 61 | f.cleaner.Clean() 62 | } 63 | -------------------------------------------------------------------------------- /structural/facade/facade_test.go: -------------------------------------------------------------------------------- 1 | package facade 2 | 3 | func ExampleFacade() { 4 | facade := NewFacade() 5 | facade.Order() 6 | // Output: 7 | // 开始为用户服务 8 | // 下厨烹饪 9 | // 开始为用户服务 10 | // 开始清洁卫生 11 | } 12 | -------------------------------------------------------------------------------- /structural/flyweight/README.md: -------------------------------------------------------------------------------- 1 | ## 享元模式 2 | 3 | 享元模式(Flyweight Pattern)会从对象中提取出公共部分并创建享元对象。 这些享元对象 (服装) 随后可在多个对象 (玩家) 中分享。 这极大地减少了服装对象的数量, 更棒的是即便你创建了更多玩家, 也只需这么两个服装对象就足够了。 4 | -------------------------------------------------------------------------------- /structural/flyweight/flyweight.go: -------------------------------------------------------------------------------- 1 | package flyweight 2 | 3 | import "fmt" 4 | 5 | // Dress 享元接口,定义了获取皮肤颜色的方法 6 | type Dress interface { 7 | Color() string 8 | } 9 | 10 | // TerroristDress 具体的恐怖分子皮肤对象,实现了 Dress 接口 11 | type TerroristDress struct { 12 | color string 13 | } 14 | 15 | // NewTerroristDress 实例化恐怖分子皮肤对象 16 | func NewTerroristDress() *TerroristDress { 17 | return &TerroristDress{color: "red"} // 红色皮肤 18 | } 19 | 20 | // Color 获取恐怖分子皮肤的颜色 21 | func (t *TerroristDress) Color() string { 22 | return t.color 23 | } 24 | 25 | // CounterTerroristDress 具体的反恐精英皮肤对象,实现了 Dress 接口 26 | type CounterTerroristDress struct { 27 | color string 28 | } 29 | 30 | // NewCounterTerroristDress 实例化反恐精英皮肤对象 31 | func NewCounterTerroristDress() *CounterTerroristDress { 32 | return &CounterTerroristDress{color: "green"} // 绿色皮肤 33 | } 34 | 35 | // Color 获取反恐精英皮肤的颜色 36 | func (t *CounterTerroristDress) Color() string { 37 | return t.color 38 | } 39 | 40 | // 享元的工厂 41 | const ( 42 | // 恐怖分子皮肤类型 43 | TerroristDressType = "terrorist" 44 | // 反恐精英皮肤类型 45 | CounterTerroristDressType = "counterTerrorist" 46 | ) 47 | 48 | // DressFactory 皮肤工厂,负责管理不同类型的皮肤对象 49 | type DressFactory struct { 50 | store map[string]Dress 51 | } 52 | 53 | // GetDress 根据皮肤类型获取皮肤对象 54 | func (d *DressFactory) GetDress(dress string) (Dress, error) { 55 | // 如果已经创建过对象就直接返回,实现享元模式,减少对象创建 56 | if d.store[dress] != nil { 57 | return d.store[dress], nil 58 | } 59 | 60 | // 根据皮肤类型实例化相应皮肤对象 61 | if dress == TerroristDressType { 62 | d.store[dress] = NewTerroristDress() 63 | return d.store[dress], nil 64 | } 65 | 66 | if dress == CounterTerroristDressType { 67 | d.store[dress] = NewCounterTerroristDress() 68 | return d.store[dress], nil 69 | } 70 | 71 | return nil, fmt.Errorf("Wrong dress type passed") 72 | } 73 | 74 | var dressFactory = &DressFactory{store: make(map[string]Dress)} 75 | 76 | // GetDressFactory 获取皮肤工厂实例 77 | func GetDressFactory() *DressFactory { 78 | return dressFactory 79 | } 80 | 81 | // Player 玩家结构体,包含玩家类型和所使用的皮肤 82 | type Player struct { 83 | dress Dress 84 | playerType string // 玩家类型,T代表恐怖分子,CT代表反恐精英 85 | } 86 | 87 | // newPlayer 创建新的玩家实例 88 | func newPlayer(playerType, dressType string) *Player { 89 | dress, _ := GetDressFactory().GetDress(dressType) 90 | return &Player{playerType: playerType, dress: dress} 91 | } 92 | 93 | // Game 游戏结构体,包含恐怖分子和反恐精英玩家列表 94 | type Game struct { 95 | terrorists []*Player 96 | counterTerrorists []*Player 97 | } 98 | 99 | // NewGame 创建新的游戏实例 100 | func NewGame() *Game { 101 | return &Game{ 102 | terrorists: make([]*Player, 0), 103 | counterTerrorists: make([]*Player, 0), 104 | } 105 | } 106 | 107 | // AddTerrorist 向游戏中添加恐怖分子玩家 108 | func (g *Game) AddTerrorist(dressType string) { 109 | player := newPlayer("T", dressType) 110 | g.terrorists = append(g.terrorists, player) 111 | return 112 | } 113 | 114 | // AddCounterTerrorist 向游戏中添加反恐精英玩家 115 | func (g *Game) AddCounterTerrorist(dressType string) { 116 | player := newPlayer("CT", dressType) 117 | g.counterTerrorists = append(g.counterTerrorists, player) 118 | return 119 | } 120 | -------------------------------------------------------------------------------- /structural/flyweight/flyweight_test.go: -------------------------------------------------------------------------------- 1 | package flyweight 2 | 3 | import "fmt" 4 | 5 | func ExampleFlyweight() { 6 | game := NewGame() 7 | 8 | // 添加恐怖分子玩家 9 | game.AddTerrorist(TerroristDressType) 10 | game.AddTerrorist(TerroristDressType) 11 | game.AddTerrorist(TerroristDressType) 12 | game.AddTerrorist(TerroristDressType) 13 | 14 | // 添加反恐精英玩家 15 | game.AddCounterTerrorist(CounterTerroristDressType) 16 | game.AddCounterTerrorist(CounterTerroristDressType) 17 | game.AddCounterTerrorist(CounterTerroristDressType) 18 | 19 | // 打印各个皮肤类型及颜色 20 | for dressType, dress := range GetDressFactory().store { 21 | fmt.Printf("DressColorType: %s\nDressColor: %s\n", dressType, dress.Color()) 22 | } 23 | // Output: 24 | // DressColorType: terrorist 25 | // DressColor: red 26 | // DressColorType: counterTerrorist 27 | // DressColor: green 28 | } 29 | -------------------------------------------------------------------------------- /structural/proxy/README.md: -------------------------------------------------------------------------------- 1 | ## 代理模式 2 | 3 | 代理模式(Proxy Pattern)为其他对象提供一种代理以控制对这个对象的访问。 4 | -------------------------------------------------------------------------------- /structural/proxy/proxy.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import "fmt" 4 | 5 | // 买车行为接口 6 | type IBuyCar interface { 7 | BuyCar() 8 | } 9 | 10 | // 用户买车 11 | type User struct { 12 | Name string 13 | } 14 | 15 | func NewUser(name string) *User { 16 | return &User{Name: name} 17 | } 18 | 19 | func (u *User) BuyCar() { 20 | fmt.Printf("<%s>买车\n", u.Name) 21 | } 22 | 23 | // 4S 店代理帮你买车 24 | type FoursMarketProxy struct { 25 | User *User 26 | } 27 | 28 | func NewFoursMarketProxy(user *User) *FoursMarketProxy { 29 | return &FoursMarketProxy{User: user} 30 | } 31 | 32 | func (f *FoursMarketProxy) BuyCar() { 33 | fmt.Println("汽车上牌子") 34 | fmt.Println("注册汽车") 35 | fmt.Println("从供应商购买汽车到 4S 店") 36 | f.User.BuyCar() 37 | fmt.Println("保养汽车") 38 | fmt.Println("维修汽车") 39 | } 40 | -------------------------------------------------------------------------------- /structural/proxy/proxy_test.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | func ExampleProxy() { 4 | foursMarket := NewFoursMarketProxy(NewUser("小明")) 5 | foursMarket.BuyCar() 6 | // Output: 7 | // 汽车上牌子 8 | // 注册汽车 9 | // 从供应商购买汽车到 4S 店 10 | // <小明>买车 11 | // 保养汽车 12 | // 维修汽车 13 | } 14 | -------------------------------------------------------------------------------- /synchronization/condition/README.md: -------------------------------------------------------------------------------- 1 | ## 条件变量模式 2 | 3 | 条件变量模式(Condition Variable Pattern)用于线程或协程之间的同步和通信。在该模式中,一个或多个线程或协程等待某个特定条件的变化,然后再继续执行其他操作。Condition Variable 模式通常与 Mutex 或 RWMutex 配合使用,用于实现线程安全的等待和通知机制。 4 | -------------------------------------------------------------------------------- /synchronization/condition/condition.go: -------------------------------------------------------------------------------- 1 | package condition 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // Data 结构体表示存储数据的对象 9 | type Data struct { 10 | ready bool // ready 表示数据是否准备好的标志 11 | cond *sync.Cond // cond 用于实现条件变量 12 | } 13 | 14 | // NewData 创建一个新的 Data 实例,并初始化 cond 为一个带锁的条件变量 15 | func NewData() *Data { 16 | return &Data{ 17 | ready: false, 18 | cond: sync.NewCond(&sync.Mutex{}), 19 | } 20 | } 21 | 22 | // WaitForReady 等待数据准备的方法 23 | func (d *Data) WaitForReady() { 24 | d.cond.L.Lock() 25 | defer d.cond.L.Unlock() 26 | 27 | for !d.ready { 28 | // 等待 cond 的条件变量满足 29 | d.cond.Wait() 30 | } 31 | 32 | fmt.Println("Data is ready") 33 | } 34 | 35 | // SetReady 设置数据准备好的方法 36 | func (d *Data) SetReady() { 37 | d.cond.L.Lock() 38 | defer d.cond.L.Unlock() 39 | 40 | // 设置数据准备好的标志为 true 41 | d.ready = true 42 | // 通知等待的线程条件已满足 43 | d.cond.Signal() 44 | } 45 | -------------------------------------------------------------------------------- /synchronization/condition/condition_test.go: -------------------------------------------------------------------------------- 1 | package condition 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestConditionVariable(t *testing.T) { 9 | data := NewData() 10 | 11 | go func() { 12 | data.WaitForReady() 13 | }() 14 | 15 | // 模拟数据准备过程 16 | fmt.Println("Preparing data...") 17 | // 模拟数据准备完毕 18 | data.SetReady() 19 | 20 | // 等待子协程完成 21 | fmt.Println("Waiting for sub goroutine to finish...") 22 | // 这里可以做其他操作 23 | } 24 | -------------------------------------------------------------------------------- /synchronization/lockmutex/README.md: -------------------------------------------------------------------------------- 1 | ## 互斥锁模式 2 | 3 | 互斥锁模式(Lock/Mutex Pattern)模式是一种常见的并发编程设计模式,用于实现线程或协程间的互斥访问控制。在该模式中,通过使用锁(Lock)或互斥体(Mutex)来保护临界区域,确保同一时刻只有一个线程或协程能够访问共享资源。这种方式可以避免数据竞争和并发访问冲突,从而确保程序的正确性和稳定性。 4 | -------------------------------------------------------------------------------- /synchronization/lockmutex/lockmutex.go: -------------------------------------------------------------------------------- 1 | package lockmutex 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // Counter 结构体用于实现一个计数器对象 9 | type Counter struct { 10 | mu sync.Mutex // 互斥锁用于保护计数器的并发访问 11 | count int // count 记录计数器的当前值 12 | } 13 | 14 | // NewCounter 创建一个新的计数器实例 15 | func NewCounter() *Counter { 16 | return &Counter{} 17 | } 18 | 19 | // Increment 增加计数器的方法 20 | func (c *Counter) Increment() { 21 | c.mu.Lock() // 加锁,防止并发访问 22 | defer c.mu.Unlock() // 延迟解锁,确保互斥锁被正确释放 23 | 24 | c.count++ // 增加计数器的值 25 | fmt.Println("增加后的计数:", c.count) 26 | } 27 | -------------------------------------------------------------------------------- /synchronization/lockmutex/lockmutex_test.go: -------------------------------------------------------------------------------- 1 | package lockmutex 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | // TestLockMutex 是对 Lock/Mutex 模式的测试函数 9 | func TestLockMutex(t *testing.T) { 10 | // 创建一个新的计数器实例 11 | counter := NewCounter() 12 | 13 | var wg sync.WaitGroup 14 | // 启动5个协程并发执行增加计数器操作 15 | for i := 0; i < 5; i++ { 16 | wg.Add(1) 17 | go func() { 18 | defer wg.Done() 19 | // 调用计数器的增加方法 20 | counter.Increment() 21 | }() 22 | } 23 | 24 | // 等待所有协程完成 25 | wg.Wait() 26 | } 27 | -------------------------------------------------------------------------------- /synchronization/monitor/README.md: -------------------------------------------------------------------------------- 1 | ## 监视器模式 2 | 3 | 监视器模式(Monitor Pattern)是一种并发编程设计模式,用于实现线程或协程之间的协作和资源共享。在 Monitor 模式中,通过将数据和操作封装在一个统一的抽象数据类型(Monitor)中,实现对共享资源的访问控制和同步。通过使用条件变量和互斥锁等同步机制,Monitor 模式提供了一种安全且高效的方法来处理并发访问和通信问题。 4 | -------------------------------------------------------------------------------- /synchronization/monitor/monitor.go: -------------------------------------------------------------------------------- 1 | package monitor 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // Monitor 结构体定义了 Monitor(监视器)类型 9 | type Monitor struct { 10 | mu sync.Mutex // 互斥锁用于保护共享资源 11 | cond *sync.Cond // 条件变量用于协调协程的同步 12 | data int // 共享数据 13 | } 14 | 15 | // NewMonitor 创建并返回一个新的 Monitor 实例 16 | func NewMonitor() *Monitor { 17 | m := &Monitor{} 18 | m.cond = sync.NewCond(&m.mu) // 使用 Monitor 结构体中的互斥锁创建条件变量 19 | return m 20 | } 21 | 22 | // WriteData 方法用于向 data 写入数据并发送信号通知等待的协程 23 | func (m *Monitor) WriteData(d int) { 24 | m.mu.Lock() // 加锁 25 | defer m.mu.Unlock() // 延迟解锁 26 | 27 | m.data = d 28 | fmt.Println("已写入数据:", d) 29 | m.cond.Signal() // 发送信号通知等待的协程 30 | } 31 | 32 | // ReadData 方法用于等待 data 被设置后读取数据 33 | func (m *Monitor) ReadData() int { 34 | m.mu.Lock() // 加锁 35 | defer m.mu.Unlock() // 延迟解锁 36 | 37 | for m.data == 0 { 38 | m.cond.Wait() // 等待条件变量满足 39 | } 40 | fmt.Println("已读取数据:", m.data) 41 | return m.data 42 | } 43 | -------------------------------------------------------------------------------- /synchronization/monitor/monitor_test.go: -------------------------------------------------------------------------------- 1 | package monitor 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestMonitor(t *testing.T) { 9 | // 创建一个新的 Monitor 实例 10 | monitor := NewMonitor() 11 | 12 | // 启动一个协程,调用 WriteData 方法向 Monitor 写入数据 13 | go func() { 14 | monitor.WriteData(10) 15 | }() 16 | 17 | // 等待数据被写入并读取 18 | data := monitor.ReadData() 19 | fmt.Println("已读取数据:", data) 20 | } 21 | -------------------------------------------------------------------------------- /synchronization/pubsub/pubsub.go: -------------------------------------------------------------------------------- 1 | package pubsub 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | /* 9 | 将消息发送给主题 10 | 设计思想: 11 | 12 | publisher结构体中包含属性为subscribers的map结构,该map key为channel, 通过Publish方法,将消息发送到channel中 13 | */ 14 | type ( 15 | subscriber chan interface{} 16 | topicFunc func(v interface{}) bool 17 | ) 18 | 19 | type Publisher struct { 20 | m sync.RWMutex //读写锁 21 | buffer int //订阅队列的大小 22 | timeout time.Duration //发布超时时间 23 | subscribers map[subscriber]topicFunc //订阅者信息 24 | } 25 | 26 | // 构建发布者对象,设置订阅队列的大小和超时时间 27 | func NewPublisher(buf int, t time.Duration) *Publisher { 28 | return &Publisher{ 29 | buffer: buf, 30 | timeout: t, 31 | subscribers: make(map[subscriber]topicFunc), 32 | } 33 | } 34 | 35 | // 添加一个订阅者,订阅所有的主题 36 | func (p *Publisher) Subscribe() subscriber { 37 | return p.SubscribeTopic(nil) 38 | } 39 | 40 | // 添加一个订阅者,订阅指定的主题 41 | func (p *Publisher) SubscribeTopic(topic topicFunc) subscriber { 42 | ch := make(subscriber, p.buffer) 43 | p.m.Lock() 44 | defer p.m.Unlock() 45 | p.subscribers[ch] = topic 46 | return ch 47 | } 48 | 49 | // 退出订阅, 同时关闭chan 50 | func (p *Publisher) Exit(sub subscriber) { 51 | p.m.Lock() 52 | defer p.m.Unlock() 53 | delete(p.subscribers, sub) 54 | close(sub) 55 | } 56 | 57 | // 关闭发布者,同时关闭所有订阅者通道 58 | func (p *Publisher) Close() { 59 | p.m.Lock() 60 | defer p.m.Unlock() 61 | 62 | for sub := range p.subscribers { 63 | delete(p.subscribers, sub) 64 | close(sub) 65 | } 66 | } 67 | 68 | // 发布主题 69 | func (p *Publisher) Publish(v interface{}) { 70 | p.m.Lock() 71 | defer p.m.Unlock() 72 | var wg sync.WaitGroup 73 | for sub, topic := range p.subscribers { 74 | wg.Add(1) 75 | go p.sendTopic(sub, topic, v, &wg) 76 | } 77 | wg.Wait() 78 | } 79 | 80 | // 发送主题, 使用select语句处理channel, 允许超时 81 | func (p *Publisher) sendTopic(sub subscriber, topic topicFunc, v interface{}, wg *sync.WaitGroup) { 82 | defer wg.Done() 83 | if topic != nil && !topic(v) { 84 | return 85 | } 86 | select { 87 | case sub <- v: 88 | case <-time.After(p.timeout): 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /synchronization/readwritelock/README.md: -------------------------------------------------------------------------------- 1 | ## 读写锁模式 2 | 3 | 读写锁模式(Read-Write Lock Pattern)模式是一种常见的设计模式,用于管理共享资源的读写访问。该模式在读多写少的场景中能够提高并发性能,有效地降低读操作之间的竞争,同时保证写操作的互斥。本文将详细介绍 Read-Write Lock 模式的概念、实现原理以及在 Go 语言中的应用示例。 4 | -------------------------------------------------------------------------------- /synchronization/readwritelock/readwritelock.go: -------------------------------------------------------------------------------- 1 | package readwritelock 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | // Data 结构体定义了包含读写锁和数据值的类型 8 | type Data struct { 9 | rwLock sync.RWMutex // 读写锁,用于并发访问控制 10 | value int // 数据值 11 | } 12 | 13 | // Read 方法用于读取数据值,使用读锁定保证并发安全 14 | func (d *Data) Read() int { 15 | d.rwLock.RLock() // 读锁定 16 | defer d.rwLock.RUnlock() // 延迟释放读锁 17 | 18 | return d.value 19 | } 20 | 21 | // Write 方法用于写入数据值,使用写锁定保证并发安全 22 | func (d *Data) Write(val int) { 23 | d.rwLock.Lock() // 写锁定 24 | defer d.rwLock.Unlock() // 延迟释放写锁 25 | 26 | d.value = val 27 | } 28 | -------------------------------------------------------------------------------- /synchronization/readwritelock/readwritelock_test.go: -------------------------------------------------------------------------------- 1 | package readwritelock 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | func TestReadWriteLock(t *testing.T) { 10 | data := Data{value: 0} 11 | 12 | var wg sync.WaitGroup 13 | 14 | // 多个 goroutine 进行读操作 15 | for i := 0; i < 3; i++ { 16 | wg.Add(1) 17 | go func() { 18 | defer wg.Done() 19 | fmt.Println("Read data:", data.Read()) 20 | }() 21 | } 22 | 23 | // 单个 goroutine 进行写操作 24 | wg.Add(1) 25 | go func() { 26 | defer wg.Done() 27 | data.Write(10) 28 | }() 29 | 30 | // 等待所有 goroutine 完成 31 | wg.Wait() 32 | } 33 | -------------------------------------------------------------------------------- /synchronization/rwlock/rwlock.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "net" 6 | ) 7 | 8 | type Socket string 9 | type Peer interface { 10 | socket Socket 11 | connection net.Conn 12 | } 13 | 14 | func (p *Peer) Socket() Socket { 15 | return p.socket 16 | } 17 | 18 | // Router hash table to associate Socket with Peers. 19 | // Unstructured mesh architecture 20 | // eg. {127.0.0.1:4000: Peer} 21 | type Router struct { 22 | sync.RWMutex 23 | table map[Socket]Peer 24 | } 25 | 26 | 27 | // Return connection interface based on socket 28 | func (r *Router) Query(socket Socket) *Peer { 29 | // Mutex for reading topics. 30 | // Do not write while topics are read. 31 | // Write Lock can’t be acquired until all Read Locks are released. 32 | r.RWMutex.RLock() 33 | defer r.RWMutex.RUnlock() 34 | 35 | if peer, ok := r.table[socket]; ok { 36 | return peer 37 | } 38 | 39 | return nil 40 | } 41 | 42 | // Add create new socket connection association 43 | func (r *Router) Add(peer *Peer) { 44 | // Lock write table while add operation 45 | // A blocked Lock call excludes new readers from acquiring the lock. 46 | r.RWMutex.Lock() 47 | r.table[peer.Socket()] = peer 48 | r.RWMutex.Unlock() 49 | } 50 | 51 | // Delete removes a connection from router 52 | func (r *Router) Delete(peer *Peer) { 53 | // Lock write table while delete operation 54 | // A blocked Lock call excludes new readers from acquiring the lock. 55 | r.RWMutex.Lock() 56 | delete(r.table, peer.Socket()) 57 | r.RWMutex.Unlock() 58 | } 59 | 60 | func main() { 61 | // New router 62 | router:= &Router{ 63 | table: make(map[Socket]Peer) 64 | } 65 | 66 | // !Important: 67 | // 1 - Write Lock can’t be acquired until all Read Locks are released. 68 | // 2 - A blocked Lock call excludes new readers from acquiring the lock. 69 | 70 | // Writing operation 71 | go func(r *Router){ 72 | for { 73 | // this will be running waiting for new connections 74 | /// .. some code here 75 | conn, err := listener.Accept() 76 | // eg. 192.168.1.1:8080 77 | remote := connection.RemoteAddr().String() 78 | socket := Socket(address) 79 | // New peer 80 | peer := &Peer{ 81 | socket: socket, 82 | connection: conn 83 | } 84 | // Here we need a write lock to avoid race condition 85 | r.Add(peer) 86 | } 87 | }(router) 88 | 89 | // Reading operation 90 | go func(r *Router){ 91 | // ...some logic here 92 | // reading operation 1 93 | connection := r.Query("192.168.1.1:8080") 94 | //... more code here 95 | // reading operation 2 96 | otherQuery:= r.Query("192.168.1.1:8081") 97 | // read locks are like counters.. 98 | // until counter = 0 Write can be acquired 99 | }(router) 100 | 101 | 102 | } 103 | -------------------------------------------------------------------------------- /synchronization/semaphore/README.md: -------------------------------------------------------------------------------- 1 | ## 信号量模式 2 | 3 | 信号量模式(Semaphore Pattern)是一种用于控制对共享资源的访问权限的并发设计模式。在并发编程中,信号量可以用来限制同时访问某个资源的并发数量,从而避免资源的过度利用和竞争条件。 4 | -------------------------------------------------------------------------------- /synchronization/semaphore/semaphore.go: -------------------------------------------------------------------------------- 1 | // Package semaphore 实现了 Go 中的信号量弹性模式。 2 | package semaphore 3 | 4 | import ( 5 | "errors" 6 | "time" 7 | ) 8 | 9 | // ErrNoTickets 是在 Acquire 无法在配置的超时时间内从信号量中获取票证时返回的错误。 10 | var ErrNoTickets = errors.New("无法获取信号量票证") 11 | 12 | // Semaphore 实现了信号量弹性模式。 13 | type Semaphore struct { 14 | sem chan struct{} // sem 是一个通道,用于表示信号量 15 | timeout time.Duration // timeout 指定等待获取票证的持续时间 16 | } 17 | 18 | // New 使用给定的票证数量和超时时间构造一个新的 Semaphore。 19 | func New(tickets int, timeout time.Duration) *Semaphore { 20 | return &Semaphore{ 21 | sem: make(chan struct{}, tickets), // 使用指定数量的票证初始化信号量通道 22 | timeout: timeout, // 设置获取票证的超时时间 23 | } 24 | } 25 | 26 | // Acquire 尝试从信号量中获取一个票证。如果成功,返回 nil。 27 | // 如果在超时时间内无法获取,则返回 ErrNoTickets。在单个 Semaphore 上并发调用 Acquire 是安全的。 28 | func (s *Semaphore) Acquire() error { 29 | select { 30 | case s.sem <- struct{}{}: // 尝试发送一个空结构体到信号量通道 31 | return nil 32 | case <-time.After(s.timeout): 33 | return ErrNoTickets 34 | } 35 | } 36 | 37 | // Release 将一个已获取的票证释放回信号量。在单个 Semaphore 上并发调用 Release 是安全的。 38 | // 在未先获取票证的 Semaphore 上调用 Release 是错误的。 39 | func (s *Semaphore) Release() { 40 | <-s.sem 41 | } 42 | 43 | // IsEmpty 在某一时刻如果没有任何票证被持有,则返回 true。 44 | // 可以与 Acquire 和 Release 并发调用 IsEmpty,但请注意结果可能不可预测。 45 | func (s *Semaphore) IsEmpty() bool { 46 | return len(s.sem) == 0 47 | } 48 | -------------------------------------------------------------------------------- /synchronization/semaphore/semaphore_test.go: -------------------------------------------------------------------------------- 1 | package semaphore 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestSemaphoreAcquireRelease(t *testing.T) { 10 | sem := New(3, 1*time.Second) 11 | 12 | for i := 0; i < 10; i++ { 13 | if err := sem.Acquire(); err != nil { 14 | t.Error(err) 15 | } 16 | if err := sem.Acquire(); err != nil { 17 | t.Error(err) 18 | } 19 | if err := sem.Acquire(); err != nil { 20 | t.Error(err) 21 | } 22 | sem.Release() 23 | sem.Release() 24 | sem.Release() 25 | } 26 | } 27 | 28 | func TestSemaphoreBlockTimeout(t *testing.T) { 29 | sem := New(1, 200*time.Millisecond) 30 | 31 | if err := sem.Acquire(); err != nil { 32 | t.Error(err) 33 | } 34 | 35 | start := time.Now() 36 | if err := sem.Acquire(); err != ErrNoTickets { 37 | t.Error(err) 38 | } 39 | if start.Add(200 * time.Millisecond).After(time.Now()) { 40 | t.Error("semaphore did not wait long enough") 41 | } 42 | 43 | sem.Release() 44 | if err := sem.Acquire(); err != nil { 45 | t.Error(err) 46 | } 47 | } 48 | 49 | func TestSemaphoreEmpty(t *testing.T) { 50 | sem := New(2, 200*time.Millisecond) 51 | 52 | if !sem.IsEmpty() { 53 | t.Error("semaphore should be empty") 54 | } 55 | 56 | sem.Acquire() 57 | 58 | if sem.IsEmpty() { 59 | t.Error("semaphore should not be empty") 60 | } 61 | 62 | sem.Release() 63 | 64 | if !sem.IsEmpty() { 65 | t.Error("semaphore should be empty") 66 | } 67 | } 68 | 69 | func ExampleSemaphore() { 70 | sem := New(2, 1*time.Second) 71 | 72 | for i := 0; i < 5; i++ { 73 | go func() { 74 | if err := sem.Acquire(); err != nil { 75 | fmt.Println(err) 76 | return // 无法获取信号量 77 | } 78 | defer sem.Release() 79 | time.Sleep(2 * time.Second) 80 | 81 | return // 在信号量保护下执行某些操作 82 | }() 83 | } 84 | 85 | time.Sleep(5 * time.Second) 86 | // Output: 87 | // 无法获取信号量票证 88 | // 无法获取信号量票证 89 | // 无法获取信号量票证 90 | } 91 | --------------------------------------------------------------------------------