给定下面的Java代码,您可以static final
在Ruby类中最接近地表示这两个变量吗?而且,在Ruby中是否可以像Java中那样区分private static
和public 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[])
{
...
}
}
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
这是另一个:
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
(不同之处在于,第一个示例是惰性的,仅在首次调用相应的属性读取器时才初始化实例变量。第二个示例将在类主体执行后立即对其进行初始化,即使它们不再需要也是如此,就像Java版本。)
让我们在这里讨论一些概念。
在Ruby中,就像其他所有“适当”(针对“适当”的各种定义)面向对象语言一样,状态(实例变量,字段,属性,插槽,属性,无论您想称呼它们如何)始终是私有的。有没有办法从外部访问它们。与对象通信的唯一方法是通过发送消息。
[注意:每当我写“没有办法”,“总是”,“唯一的办法”等字眼时,实际上它的意思是“没有办法,除了反射”。在这种特定情况下,Object#instance_variable_set
例如有。]
换句话说:在Ruby中,变量始终是私有的,访问它们的唯一方法是通过getter和/或setter方法,或者在Ruby中称为属性读取器和/或写入器。
现在,我继续写实例变量,但是在Java示例中,我们有静态字段,即类变量。嗯,在Ruby中,与Java不同,类也是对象。它们是Class
类的实例,因此,就像其他任何对象一样,它们可以具有实例变量。因此,在Ruby中,类变量的等效项实际上只是一个标准实例变量,属于一个恰好是类的对象。
(也有类层次结构变量,在符号上用双符号表示@@sigil
。它们确实很奇怪,您可能应该忽略它们。类层次结构变量在整个类层次结构(即它们所属的类,所有子类和它们的子类及其子类...以及所有这些类的所有实例。实际上,它们更像是全局变量而不是类变量,应该真正地调用它们$$var
而不是@@var
,因为与实例相比,它们与全局变量的关系更为密切变量。它们并不是完全没用,但很少有用。)
因此,我们介绍了“字段”部分(Java字段== Ruby实例变量),介绍了“ public”和“ private”部分(在Ruby中,实例变量始终是私有的,如果您想将它们设为公开,使用公共的getter / setter方法),我们已经介绍了“静态”部分(Java静态字段== Ruby类实例变量)。那“最终”部分呢?
在Java中,“最终”只是拼写“ const”的一种有趣方式,设计人员避免了这种做法,因为const
诸如C和C ++之类的语言中的关键字被巧妙地打乱了,他们不想使人们感到困惑。Ruby 确实有常量(以大写字母开头)。不幸的是,它们并不是真正恒定的,因为在生成警告的同时尝试对其进行修改实际上是可行的。因此,它们更像是约定,而不是编译器强制的规则。但是,常量的更重要限制是它们始终是公共的。
因此,常量几乎是完美的:它们不能被修改(嗯,它们不应该被修改),即它们是final
,它们属于一个类(或模块),即它们是static
。但是它们始终是public
,因此很遗憾,它们不能用于建模private static final
字段。
这正是思考问题而不是解决方案的关键所在。您想要什么?你想说
您可以用Java中完全不同的方式实现所有这些目标:
||=
复合分配仅分配一次您唯一需要担心的是,您没有分配给@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
请注意,与我的答案顶部的版本之间的细微但重要的区别是:缺少@
标记。在这里,我们正在创建局部变量,而不是实例变量。类主体结束后,这些局部变量将超出范围,并且永远无法再次访问。只有它定义两个getter方法两大块仍然可以访问他们,因为他们接近了类体。现在,它们实际上是私有的,它们是final
,因为在整个程序中唯一仍然可以访问它们的就是纯吸气方法。
这可能不是惯用的Ruby,但是对于任何具有Lisp或JavaScript背景的人来说,它应该足够清楚。这也非常优雅。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句