Ruby中静态值的方法与常量的使用

170 阅读2分钟

最近,我参加了一个团队,偶然发现要把一个传统的库重写成一个新的、更新的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 ,作为一个公开的、有记录的访问器。