之前在写一个限流器的时候,习惯性的用了选项模式来配置
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),
}
}
相比于这种直接配置的方式,选项模式的优点在哪里呢?感觉扩展性和可读性也没有提升,这种方式也可以链式调用。
我个人想的可能是不暴露修改的接口,在调用构造函数以后就不会被修改了安全一点。
除了这一个以外还有其他的考量吗?希望听听各位大大的分析
个人经验来参考:
*LeakyLimiter
是一致的,如果改成对象调整,当 A、B 两个依赖这个服务的指针会因为内部变化而影响另外一个。关于第二点的补充:比如,
c2
和c1
因为调用的是同一个l
,因为l.WithCount(3)
导致l
会互相影响