最近,我参加了一个团队,偶然发现要把一个传统的库重写成一个新的、更新的API。这个API将作为长期发展的基础,所以我们花了一些时间来设计好它。
我们不得不在API设计的许多方面达成一致,其中之一就是我们要如何定义静态值。即使是像保留队列的名称这样简单的东西(万一你要建立一个工作框架),至少也有3种方法来定义它。
# Option 1
class Queue
RESERVED_QUEUE = "reserved"
end
# Option 2
class Queue
def self.reserved_queue
"reserved"
end
end
# Option 3
class Queue
RESERVED_QUEUE = "reserved"
def self.reserved_queue
RESERVED_QUEUE
end
end
在旧版本的Ruby中,由于重复的字符串分配,选项2的性能很差--然而,有了冻结的字符串字面,这不再是一个问题,所有选项的性能都是一样的。
那么,你会在什么时候选择选项1、2或3呢?
我个人会完全拒绝选项3,因为当Ruby缺乏冻结的字符串字面时,它是一种编写优化Ruby的方法。你不再需要这样做了,而且由于Ruby的目的是优雅,你应该使用更简单的形式,而不需要将所有重复的字符串包裹成常量。而且对于外部读者来说,与其他选项相比,它引入了一个额外的跳跃:你必须从reserved_queue 的调用者到def reserved_queue ,然后再到RESERVED_QUEUE 中的实际值。
这就留下了选项1和2。发生了一些争论,我的一位伟大的同事提到,如果某些东西是静态的,那么常量比方法要好。我无法反驳这一点,但我也关心一个很好的外部API,以防该值在同一模块之外被消费。
我能够制定一个经验法则,让你选择正确的方法。
- 如果你希望该值的消费者在同一模块内,就把它定义为一个私有常量(选项1)。
- 如果你希望消费者在模块之外,这使得静态值公开暴露,这意味着将其定义为方法可能是最好的(选项2)。
换句话说,一个API的消费者住在哪里决定了它应该是一个常量还是一个方法。
在上面的例子中,保留的队列名称已经在代码库中被广泛使用,这使得我们选择Queue.reserved_queue ,作为一个公开的、有记录的访问器。