【问题标题】:Private class (not class method) in a Ruby module?Ruby模块中的私有类(不是类方法)?
【发布时间】:2011-03-30 14:31:32
【问题描述】:

我是 Ruby 新手(熟悉 Python、C++ 和 C)。我需要创建一个仅由模块中的其他类和方法使用的类。在 Python 中,我只称它为 __classname。我会在 C++ 中使用空的 typedef。我如何在 Ruby 中做到这一点(或者我是在找错树,而不是按照“Ruby 方式”做到这一点?)

【问题讨论】:

    标签: ruby oop class private


    【解决方案1】:

    要意识到的最重要的事情是,一个类并没有什么特别之处。它只是一个对象。按照惯例,类被分配给常量,但没有什么说它们必须

    由于类与任何其他对象一样只是对象,因此您将它们设为私有就像将任何其他对象设为私有一样。

    以下是我能想到的可能性,按照私密性增加的顺序排列:

    1. 只需将它们嵌套在命名空间(即模块)中即可。在 Ruby 中,通常期望库的所有模块和类都位于与库同名的命名空间中(即my_awesome_libraryMyAwesomeLibrary),但一般来说,嵌套在该命名空间下的所有内容都是被认为是私人的。事实上,除了Test::Unit::TestCase,我想不出一个真正期望客户端代码使用的三层深度命名空间的例子。
    2. 与 1. 相同,但将其命名为明显的名称,例如 MyAwesomeLibrary::Internal::FfiStruct
    3. 与 1. 或 2. 相同,并用:nodoc: RDoc 标签标记。
    4. 类似于 3.,但使用更现代的文档系统,例如 YARD,它实际上允许您显式标记私有 API。
    5. 使用方法而不是常量。方法可以设为私有。 (为了保持一致性,您可以让方法名称以大写字母开头,使其类似于常量。没有什么可以阻止的,snake_case 约定就是这样:约定。)
    6. 使用实例变量。他们总是私人的。请注意,可以使用反射轻松访问私有方法和实例变量。不过,send 似乎比 instance_variable_get 更广泛地使用,这就是为什么我认为实例变量比方法具有更高级别的隐私。
    7. 实际上,获得实际隐私或封装的唯一方法是使用局部变量和闭包。但是请注意,这可能会阻止您使用 Ruby 的模块、类或方法定义语法,因为它们会创建新的范围。在所有需要访问课程的情况下,您都需要使用Module.newClass.newModule#define_method

    例如:

    module MyAwesomeLibrary
      struct = Class.new(FFI::Struct) do
        # ...
      end
    
      PublicInterface = Class.new do
        define_method(:initialize) do |bar|
          @foo = struct.new(bar)
        end
      end
    end
    

    是的,这是在 Ruby 中实现真正 100% 信息隐藏和封装的唯一方法。

    然而,普通的 Ruby 方法是简单地将这些东西记录为私有的(也许将其降低到命名空间的级别)并信任您的开发人员。在 Ruby 社区中,这有时被概括为 Python 口号“我们都是自愿的成年人”。

    【讨论】:

    • “我们都是成年人”是 Python 社区的口号,而不是 Ruby 社区。​​span>
    • 我并不是要暗示它属于 Ruby 社区,只是它在那里被使用。但你是对的,措辞具有误导性。二十年的英语学习显然还不够:-)
    【解决方案2】:

    直接从this blog post 获取此信息,但从 Ruby 1.9.3 开始,您可以使用 private_constant 在模块内创建私有类:

    class Person
      class Secret
        def to_s
          "1234vW74X&"
        end
      end
      private_constant :Secret
    
      def show_secret
        Secret.new.to_s
      end
    end
    

    【讨论】:

      【解决方案3】:

      到目前为止,我还没有在 Ruby 中看到过这样的概念,但我想你可以通过创建私有方法来模拟它,该方法将返回一个作为局部变量创建的类(请记住,在 Ruby 中,类是一个对象,就像任何其他,并且可以在方法中实例化并由它返回)。

      顺便说一句,即使是 Ruby 中的私有方法也不像其他语言那样私有 - 您始终可以使用 send 方法访问它们。但这样做意味着您知道自己在做什么。

      【讨论】:

      • 该死的。我认为这是可能的,但我希望它不会是骇人听闻的......哦,好吧。我想我会找到一种更 Ruby-ish 的方式来做到这一点。不过谢谢 - 你回答了我的问题。
      • 你应该等待其他答案,我可能是错的。顺便说一句,你想通过私人课程实现什么?哦,另一件事:实例变量在 Ruby 中总是 private,为了公开它们,您需要创建访问器方法,但没有人认为 hackish。 :)
      • 实际上我认为这样做 /is/ 有点 hackish - 这是我不喜欢 Ruby 的地方之一。另一个是愚蠢的隐式函数调用——我真的希望我可以只通过名称引用一个函数而不调用它,而不使用符号或 lambda。我正在使用 FFI 与外部库动态交互,我想让 FFI C '结构远离可用模块。
      • 恕我直言,为现有功能(例如attr_accessor 方法)轻松覆盖的功能添加语言结构将是骇人听闻的。我非常感谢 Ruby 的这种简单性,尽管我会删除更多的关键字(比如完全多余的 for)。关于函数调用,我同意你的看法。顺便说一句,我很确定可以很容易地将私有类“包装”到单个方法调用中,因此至少它不应该看起来 hackish。 :)
      猜你喜欢
      • 2010-09-24
      • 1970-01-01
      • 2021-07-20
      • 2017-09-17
      • 2014-08-26
      • 1970-01-01
      • 1970-01-01
      • 2011-04-11
      • 1970-01-01
      相关资源
      最近更新 更多