├── 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 | 
6 | 发布订阅模式往往实现为<消息代理,消息中间件,消息队列>等
7 |
8 | 该模式中的三个关键类型:消息本身、消息主题、订阅用户。
9 | 
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 | 
10 |
11 | 状态变化流:
12 |
13 | 
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 |
--------------------------------------------------------------------------------