Go常用设计模式简记-行为型模式
行为型模式(Behavioral Patterns),它的特点是关注对象之间的通信
代理模式
常用场景:需要一个替身或者占位符,以控制对这个对象的访问的场景。
代理模式 (Proxy Pattern),可以为另一个对象提供一个替身或者占位符,以控制对这个对象的访问。
下面实现中 StationProxy 代理了 Station,代理类中持有被代理类对象,并且和被代理类对象实现了同一接口。
package main
import "fmt"
//
type Seller interface {
sell(name string)
}
// 火车站
type Station struct {
stock int // 库存
}
func (s *Station) sell(name string) {
if s.stock>0 {
s.stock--
fmt.Printf("火车站中:%s买了一张票,余票:%d\n",name,s.stock)
} else {
fmt.Println("票已售空")
}
}
// 火车代理点
type StationProxy struct {
station *Station // 持有一个火车站对象
}
func (prox *StationProxy) sell(name string) {
if prox.station.stock >0 {
prox.station.stock--
fmt.Printf("代理点中:%s买了一张票,余票:%d\n",name, prox.station.stock)
} else {
fmt.Println("票已售空")
}
}
func main() {
s :=&Station{
stock: 10,
}
s.sell("张三")
fmt.Println("Other>>>>>")
prox := &StationProxy{s}
prox.sell("李四")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
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
40
41
42
43
44
45
46
47
选项模式
常用场景:
- 结构体参数很多,期望创建一个携带默认值的结构体变量,并选择性修改其中一些参数的值。
- 结构体参数经常变动,变动时又不想修改创建实例的函数
使用选项模式,我们可以创建一个带有默认值的 struct 变量,并选择性地修改其中一些参数的值。
对于实现默认值配置的方案,常见的有三种:开发多个创建实例的函数、通过创建一个带默认值的选项实例作为参数、选项模式,下面我们逐个查看其实现方式:
方式一:开发多个创建实例的函数
为实现默认值配置,分别开发两个用来创建实例的函数,一个可以创建带默认值的实例,一个可以定制化创建实例。
使用这种方式,创建同一个 Connection 实例,却要实现两个不同的函数,实现方式很不优雅。
package main
import "time"
const (
defaultTimeout = 10
defaultCaching = false
)
type Connection struct {
addr string
cache bool
timeout time.Duration
}
func NewConnect(add string)(*Connection,error) {
return &Connection{
addr: add,
cache: defaultCaching,
timeout: defaultTimeout,
},nil
}
func NewConnectWithOpt(add string,cache bool, timeout time.Duration)(*Connection,error) {
return &Connection{
addr: add,
cache: cache,
timeout: timeout,
},nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
方式二:创建一个带默认值的选项实例
创建一个带默认值的选项,并用该选项创建实例。
使用这种方式,虽然只需要实现一个函数来创建实例, 但是也有缺点:为了创建 Connection 实例,每次我们都要创建 ConnectionOptions,操作起来比较麻烦。
package main
import "time"
const (
defaultTimeoutb = 10
defaultCachingb = false
)
type Connectionb struct {
addr string
cache bool
timeout time.Duration
}
type ConnectionOptions struct {
Caching bool
Timeout time.Duration
}
func NewDefaultOptions() *ConnectionOptions {
return &ConnectionOptions{
Caching: defaultCachingb,
Timeout: defaultTimeoutb,
}
}
func NewConnectWithOps(addr string,opts *ConnectionOptions) (*Connectionb,error) {
return &Connectionb{
addr: addr,
cache: opts.Caching,
timeout: opts.Timeout,
},nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
方式三:选项模式
之前通过Java看设计模式时,没看到关于选项模式,感觉在Go中的实现也比较有特点。在解决目的上感觉和建造者模式差不太多,都是在关注通过可变参数创建对象的问题。
选项模式有很多优点,例如:支持传递多个参数,并且在参数发生变化时保持兼容性;支持任意顺序传递参数;支持默认值;方便扩展;通过 WithXXX 的函数命名,可以使参数意义更加明确,等等.
为了实现选项模式,我们增加了很多代码,如果结构体参数比较少,需慎重考虑要不要采用选项模式。
package main
import (
"fmt"
"time"
)
// 默认值
const (
defaultTimeoutc = 10
defaultCachingc = false
)
// Connection 结构体,实际需要创建的对象
type Connectionc struct {
addr string
cache bool
timeout time.Duration
}
// options 选项结构体,用于保存变量值
type options struct {
caching bool
timeout time.Duration
}
type Option interface {
apply(*options)
}
// 定义配置选项函数(关键)
type optionFunc func(*options)
// Option 类型的选项参数需要实现apply(*options)函数
func (f optionFunc) apply(o *options) {
f(o)
}
// 通过 WithXXX 方法来创建 Option 类型的选项参数
func WithTimeout(t time.Duration) Option {
return optionFunc(func(o *options) {
o.timeout = t
})
}
func WithCaching(cache bool) Option {
return optionFunc(func(o *options) {
o.caching = cache
})
}
// 创建 Connect 对象
func NewConnectc(addr string,opts ...Option)(*Connectionc,error) {
// 默认值的options
options := options{
timeout: defaultTimeoutc,
caching: defaultCachingc,
}
// 修改属性值
for _,o := range opts{
// o.apply(&options)其实就是通过闭包把 WithTimeout、WithCaching 传入的参数赋值给 options 结构体变量,以此动态地设置 options 结构体变量的属性
o.apply(&options)
}
return &Connectionc{
addr: addr,
cache: options.caching,
timeout: options.timeout,
},nil
}
func main() {
connection,_ :=NewConnectc(
"https://twst",
WithCaching(true),
)
fmt.Println("Connection fild: ", connection)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
2
3
4
5
6
7
8
9
10
11
12
13
14
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
参考资料
预览
除特别注明外,本站所有文章均为 windcoder 原创,转载请注明出处来自: gochangyongshejimoshijianji-xingweixingmoshi
Loading comments...

预览
暂无数据