Java中"private static final"和"public static final"类变量的最近Ruby表示?

Hos*_*osh 16 ruby java static private public

鉴于下面的Java代码,你能static final在Ruby类中代表这两个变量的最接近的是什么?并且,Ruby中是否有可能区分Java中的变量private staticpublic static变量?

public class DeviceController
{
  ...
  private static final Device myPrivateDevice = Device.getDevice("mydevice");
  public static final Device myPublicDevice = Device.getDevice("mydevice");
  ...
  public static void main(String args[])
  {
   ...
  }
}
Run Code Online (Sandbox Code Playgroud)

Jör*_*tag 45

Ruby中确实没有等效的构造.

然而,看起来你正在犯一个经典的移植错误:你有一个语言A 的解决方案,并尝试将其转换为语言B,当你真正应该做的是找出问题,然后弄清楚如何解决它用语言B.

我不能确定你试图从那个小代码片段解决的问题是什么,但这里有一个可能的想法,如何在Ruby中实现它:

class DeviceController
  class << self
    def my_public_device;  @my_public_device  ||= Device['mydevice'] end

    private

    def my_private_device; @my_private_device ||= Device['mydevice'] end
  end
end
Run Code Online (Sandbox Code Playgroud)

这是另一个:

class DeviceController
  @my_public_device  ||= Device['mydevice']
  @my_private_device ||= Device['mydevice']

  class << self
    attr_reader :my_public_device, :my_private_device
    private :my_private_device
  end
end
Run Code Online (Sandbox Code Playgroud)

(不同之处在于第一个示例是惰性的,它只在初始化相应的属性读取器时初始化实例变量.第二个示例在执行类主体时立即初始化它们,即使它们从不需要,就像Java版本.)

让我们来看看这里的一些概念.

在Ruby中,就像在其他所有"适当的"(对于"正确"的各种定义)面向对象语言一样,状态(实例变量,字段,属性,槽,属性,无论你想要什么,都称为它们)总是私有的.有没有办法从外部访问它们.与对象通信的唯一方法是通过发送消息.

[注意:每当我写"无路径","永远","唯一的方式"等内容时,它实际上并不意味着"没有办法,除了反思".在这种特殊情况下,Object#instance_variable_set例如有.]

换句话说:在Ruby中,变量总是私有的,访问它们的唯一方法是通过getter和/或setter方法,或者在Ruby中调用属性读取器和/或编写器.

现在,我一直在写关于实例变量,但在Java示例中我们有静态字段,即变量.好吧,在Ruby中,与Java不同,类也是对象.它们是Class类的实例,因此,就像任何其他对象一样,它们可以包含实例变量.因此,在Ruby中,等同于类变量实际上只是一个标准实例变量,它属于恰好是一个类的对象.

(也有类层次结构变量,用符号表示@@sigil.这些非常奇怪,您应该忽略它们.类层次结构变量在整个类层次结构中共享,即它们所属的类,所有子类和它们的子类及其子类...以及所有这些类的所有实例.实际上,它们更像是全局变量而不是类变量.它们应该被实际调用$$var而不是@@var,因为它们与全局变量的关系比实例更密切变量.它们并非完全没用,但很少有用.)

所以,我们已经介绍了"字段"部分(Java字段== Ruby实例变量),我们已经介绍了"公共"和"私有"部分(在Ruby中,实例变量总是私有的,如果你想让它们公开,使用公共getter/setter方法)我们已经介绍了"静态"部分(Java静态字段== Ruby类实例变量).那么"最终"部分呢?

在Java中,"final"只是拼写"const"的一种有趣方式,设计师避免使用它,因为constC和C++等语言中的关键字被巧妙地打破,并且他们不想让人混淆.Ruby 确实有常量(以大写字母开头表示).不幸的是,它们并不是真正的常量,因为在生成警告的同时尝试修改它们实际上是有效的.因此,它们更像是一种约定,而不是编译器强制规则.然而,常数的更重要的限制是它们总是公开的.

因此,常量几乎是完美的:它们不能被修改(好吧,它们不应该被修改),即它们是final,它们属于一个类(或模块),即它们是static.但它们总是public如此,不幸的是它们不能用于建模private static final领域.

这正是思考问题而不是解决方案的关键所在.你想要的是什么?你想要那样的状态

  1. 属于一个班级,
  2. 只能读不写,
  3. 只被初始化一次
  4. 可以是私人的也可以是公共的.

您可以实现所有这些,但与Java完全不同:

  1. 类实例变量
  2. 不提供setter方法,只提供getter
  3. 使用Ruby的||=复合赋值只分配一次
  4. 吸气方法

您唯一需要担心的是,您不会分配到@my_public_device任何地方,或者更好的是,根本不会访问它.始终使用getter方法.

是的,这实施中的漏洞.Ruby通常被称为"成年人的语言"或"同意成人语言",这意味着您不必让编译器强制执行某些操作,而只需将它们放在文档中并简单地相信您的开发人员已经了解到触及其他内容人民的私奔是粗鲁的......


一种完全不同的隐私方法是功能语言中使用的方法:使用闭包.闭包是代码块,它们在词汇环境中关闭,即使在词汇环境超出范围之后也是如此.这种实现私有状态的方法在Scheme中非常流行,但最近也被Douglas Crockford等人推广.对于JavaScript.这是Ruby中的一个例子:

class DeviceController
  class << self
    my_public_device, my_private_device = Device['mydevice'], Device['mydevice']

    define_method :my_public_device  do my_public_device  end
    define_method :my_private_device do my_private_device end

    private :my_private_device
  end # <- here the variables fall out of scope and can never be accessed again
end
Run Code Online (Sandbox Code Playgroud)

请注意我答案顶部版本的微妙但重要的区别:缺少@印记.在这里,我们创建局部变量,而不是实例变量.一旦类主体结束,那些局部变量就会超出范围,永远不会再被访问.只有定义两个getter方法的两个块仍然可以访问它们,因为它们靠近类体.现在,它们真的是私有的,它们是final,因为整个程序中仍然可以访问它们的唯一东西是纯粹的getter方法.

这可能不是惯用的Ruby,但对于任何具有Lisp或JavaScript背景的人来说,它应该足够清楚.它也很优雅.