-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d5646c8
Showing
4 changed files
with
299 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# go-patterns-cn | ||
|
||
|名称|是否实现| | ||
|-----|-----| | ||
|观察者模式|是| | ||
|策略模式|是| | ||
|模板方法模式|是| | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# 观察者模式 | ||
|
||
## 概念 | ||
|
||
观察者模式允许类型实例将事件“发布”到希望在发生特定事件时进行更新通知其他类型实例(“观察者”) | ||
|
||
## 使用观察者模式的场景和优缺点 | ||
|
||
### 使用场景 | ||
|
||
关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。 | ||
事件多级触发场景。 | ||
跨系统的消息交换场景,如消息队列、事件总线的处理机制。 | ||
|
||
#### 优点 | ||
|
||
- 解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换。 | ||
|
||
#### 缺点 | ||
|
||
- 在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,如果一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。 | ||
|
||
## 代码实现 | ||
|
||
```golang | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
) | ||
|
||
// Event 消息 | ||
type Event struct { | ||
Data int64 | ||
} | ||
|
||
// Observer 观察者,观察特定的消息 | ||
type Observer interface { | ||
// 消息变动通知观察者 | ||
OnNotify(Event) | ||
} | ||
|
||
// Notifier 被观察的对象 | ||
type Notifier interface { | ||
|
||
// Register 注册观察者 | ||
Register(Observer) | ||
// Deregister 删除观察者 | ||
Deregister(Observer) | ||
// Notify 消息通知 | ||
Notify(Event) | ||
} | ||
|
||
// eventObserver Observer 实现 | ||
type eventObserver struct { | ||
id int | ||
} | ||
|
||
// eventNotifier Notifier 实现 | ||
type eventNotifier struct { | ||
// 用map来存放Observer | ||
observers map[Observer]struct{} | ||
} | ||
|
||
// OnNotify 收到消息变动 | ||
func (o *eventObserver) OnNotify(e Event) { | ||
fmt.Printf("*** 观察者 %d 接受到变动的消息: %d\n", o.id, e.Data) | ||
} | ||
|
||
// Register ... | ||
func (o *eventNotifier) Register(l Observer) { | ||
o.observers[l] = struct{}{} | ||
} | ||
|
||
// Deregister ... | ||
func (o *eventNotifier) Deregister(l Observer) { | ||
delete(o.observers, l) | ||
} | ||
|
||
// Notify 把变化的消息发送给所有的观察者 | ||
func (o *eventNotifier) Notify(e Event) { | ||
for i := range o.observers { | ||
i.OnNotify(e) | ||
} | ||
} | ||
|
||
func main() { | ||
// 初始化 | ||
n := eventNotifier{ | ||
observers: map[Observer]struct{}{}, | ||
} | ||
|
||
// 注册两个观察者 | ||
n.Register(&eventObserver{id: 1}) | ||
n.Register(&eventObserver{id: 2}) | ||
|
||
// 消息通知 | ||
stop := time.NewTimer(10 * time.Second).C | ||
tick := time.NewTicker(time.Second).C | ||
for { | ||
select { | ||
case <-stop: | ||
return | ||
case t := <-tick: | ||
n.Notify(Event{Data: t.Unix()}) | ||
} | ||
} | ||
} | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# 策略模式 | ||
|
||
## 概念 | ||
|
||
- 定义一系列算法,让这些算法在运行时可以互换,使得分离算法,符合开闭原则 | ||
|
||
## 模式的场景和优缺点 | ||
|
||
### 使用场景 | ||
|
||
- 在有多种算法相似的情况下,使用 ```if...else``` 所带来的复杂和难以维护。 | ||
- 一个系统有许多许多类,而区分它们的只是他们直接的行为。 | ||
|
||
|
||
#### 策略模式优点 | ||
|
||
- 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。 | ||
- 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。 | ||
- 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。 | ||
- 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。 | ||
- 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。 | ||
|
||
#### 策略模式缺点 | ||
|
||
- 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。 | ||
- 策略模式造成很多的策略类。 | ||
|
||
## 代码实现 | ||
|
||
```golang | ||
|
||
package main | ||
|
||
import "fmt" | ||
|
||
// Operator ... | ||
type Operator interface { | ||
Apply(int, int) int | ||
} | ||
|
||
// Operation 包装器 | ||
type Operation struct { | ||
Operator Operator | ||
} | ||
|
||
// Addition ... | ||
type Addition struct{} | ||
|
||
// Apply ... | ||
func (add *Addition) Apply(left, right int) int { | ||
return left + right | ||
} | ||
|
||
// Multiplication ... | ||
type Multiplication struct{} | ||
|
||
// Apply ... | ||
func (mu *Multiplication) Apply(left, right int) int { | ||
return left * right | ||
} | ||
|
||
// Operate ... | ||
func (o *Operation) Operate(leftValue, rightValue int) int { | ||
return o.Operator.Apply(leftValue, rightValue) | ||
} | ||
|
||
// CreateOpration ... | ||
func CreateOpration(operator Operator) Operation { | ||
return Operation{operator} | ||
} | ||
|
||
func main() { | ||
var operationes []Operation | ||
operatorAdd := CreateOpration(new(Addition)) | ||
operatorMul := CreateOpration(new(Multiplication)) | ||
operationes = append(operationes, operatorAdd) | ||
operationes = append(operationes, operatorMul) | ||
for _, operator := range operationes { | ||
value := operator.Operate(1, 2) | ||
fmt.Printf("%d\n", value) | ||
} | ||
} | ||
|
||
|
||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# 模板方法模式模式 | ||
|
||
## 概念 | ||
|
||
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。 | ||
|
||
## 模板方法模式模式的场景和优缺点 | ||
|
||
### 使用场景 | ||
|
||
- 有多个子类共有的方法,且逻辑相同 | ||
- 重要的、复杂的方法,可以考虑作为模板方法 | ||
|
||
#### 优点 | ||
|
||
- 封装不变部分,扩展可变部分 | ||
- 提取公共代码,便于维护 | ||
- 行为由父类控制,子类实现 | ||
|
||
#### 缺点 | ||
|
||
- 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大 | ||
|
||
## 代码实现 | ||
|
||
```golang | ||
package main | ||
|
||
import "fmt" | ||
|
||
// Thing 定义接口 | ||
type Thing interface { | ||
SetName(name string) | ||
BeforeAction() | ||
Exit() | ||
} | ||
|
||
// Person ... | ||
type Person struct { | ||
name string | ||
Concrete Thing | ||
} | ||
|
||
// SetName ... | ||
func (p *Person) SetName(name string) { | ||
p.name = name | ||
} | ||
|
||
// BeforeAction ... | ||
func (p *Person) BeforeAction() { | ||
// | ||
p.Concrete.BeforeAction() | ||
} | ||
|
||
// Exit ... | ||
func (p *Person) Exit() { | ||
p.BeforeAction() | ||
fmt.Println(p.name + "exit") | ||
} | ||
|
||
// Boy ... | ||
type Boy struct { | ||
Person //匿名组合实现继承 | ||
} | ||
|
||
// BeforeAction ... | ||
func (b *Boy) BeforeAction() { | ||
fmt.Println(b.name) | ||
} | ||
|
||
// Girl ... | ||
type Girl struct { | ||
Person //匿名组合实现继承 | ||
} | ||
|
||
// BeforeAction ... | ||
func (g *Girl) BeforeAction() { | ||
fmt.Println(g.name) | ||
} | ||
|
||
func main() { | ||
boy := &Boy{} | ||
person := new(Person) | ||
person.SetName("boy") | ||
person.Concrete = boy | ||
//赋值boy的内容, 注意要在设定了person具体值之后赋值,否则为空 | ||
boy.Person = *person | ||
person.Exit() | ||
} | ||
|
||
|
||
``` |