Go使用选项模式的优点是什么?
之前在写一个限流器的时候,习惯性的用了选项模式来配置
type LeakyLimiter struct {
lock sync.Mutex
last time.Time
sleep time.Duration
perReq time.Duration
maxSlack time.Duration
}
type leakyOptions struct {
maxSlack time.Duration
}
type LeakyOption interface {
apply(*leakyOptions)
}
type leakyOptionFunc func(options *leakyOptions)
func (l leakyOptionFunc) apply(o *leakyOptions) {
l(o)
}
func WithMaxSlack(maxSlack time.Duration) LeakyOption {
return leakyOptionFunc(func(options *leakyOptions) {
options.maxSlack = maxSlack
})
}
func NewLeakyLimiter(rate int, opts ...LeakyOption) *LeakyLimiter {
options := leakyOptions{
maxSlack: -10 * time.Second / time.Duration(rate),
}
for _, option := range opts {
option.apply(&options)
}
return &LeakyLimiter{
perReq: time.Second / time.Duration(rate),
maxSlack: options.maxSlack,
}
}
但是突然想到,能不能直接暴露出能够修改可配置项的函数
type LeakyLimiter struct {
lock sync.Mutex
last time.Time
sleep time.Duration
perReq time.Duration
maxSlack time.Duration
}
func (l *LeakyLimiter) WithMaxSlack(maxSlack time.Duration) *LeakyLimiter {
l.maxSlack = maxSlack
return l
}
func NewLeakyLimiter(rate int) *LeakyLimiter {
return &LeakyLimiter{
perReq: time.Second / time.Duration(rate),
maxSlack: -10 * time.Second / time.Duration(rate),
}
}
相比于这种直接配置的方式,选项模式的优点在哪里呢?感觉扩展性和可读性也没有提升,这种方式也可以链式调用。我个人想的可能是不暴露修改的接口,在调用构造函数以后就不会被修改了安全一点。除了这一个以外还有其他的考量吗?希望听听各位大大的分析
回复
1个回答
test
2024-06-25
个人经验来参考:
- 因为 Go 的常驻内存,一种是初始化启动、还一种是按需启动。
- 常驻内存下,多个依赖的服务,其实希望的是
*LeakyLimiter
是一致的,如果改成对象调整,当 A、B 两个依赖这个服务的指针会因为内部变化而影响另外一个。
关于第二点的补充:比如,c2
和 c1
因为调用的是同一个 l
,因为 l.WithCount(3)
导致 l
会互相影响
package main
import "fmt"
func main() {
l := NewLimiter(5)
c1 := NewCase(l)
c2 := NewCase(l.WithCount(3))
fmt.Println(c1, c2)
}
type Case struct {
limiter *Limiter
}
func NewCase(limiter *Limiter) *Case {
return &Case{
limiter: limiter,
}
}
func (c *Case) Allow() bool {
return c.limiter.Allow()
}
type Limiter struct {
Count int
}
func NewLimiter(count int) *Limiter {
return &Limiter{
Count: count,
}
}
func (l *Limiter) WithCount(c int) *Limiter {
l.Count = c
return l
}
func (l *Limiter) Allow() bool {
return l.Count > 0
}
回复
适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容