9

来自 Java,我正在尝试在 Ruby 中实现 LinkedList。我在 Java 中实现它的常用方法是有一个名为 LinkedList 的类和一个名为 Node 的私有内部类,LinkedList 的每个对象都作为 Node 对象。

class LinkedList
  private
  class Node
    attr_accessor :val, :next
  end
end

我不想将 Node 类暴露给外部世界。但是,通过 Ruby 中的此设置,我可以使用以下方法访问 LinkedList 类之外的私有 Node 类对象 -

node = LinkedList::Node.new

我知道,在 Ruby 1.9 中,我们可以使用 private_constant 方法将 Node 指定为私有常量。但我想知道这是否是实现这一目标的正确方法?另外,为什么我能够在 LinkedList 类之外创建 Node 对象,即使它被声明为私有?

4

2 回答 2

14

为什么我能够在 LinkedList 类之外创建 Node 对象,即使它被声明为私有?

因为在 ruby​​ 常量中忽略“常规”可见性修饰符。无论它们在哪个部分,它们始终是公开的。要使它们私有,请使用private_constant. 称之为不雅的设计或其他任何东西,但事实就是如此。

另外,请注意,即使使用private_constant,隐私意义也很小。基本上,它唯一做的就是从列表 ( LinkedList.constants) 和直接解析 ( LinkedList::Node) 中隐藏常量。如果有人知道该名称,他们能够访问它。

class LinkedList
  class Node
    attr_accessor :val, :next
  end

  private_constant :Node
end

LinkedList.const_get('Node') # => LinkedList::Node
于 2016-09-27T05:46:41.290 回答
4

我知道塞尔吉奥的回答绰绰有余,但只是回答问题:

如何在 Ruby 中实现私有内部类

你也可以选择:

class LinkedList
  class << self
    class Node
    end

    def some_class_method
      puts Node.name
    end
  end
end

LinkedList.some_class_method        # accessible inside class
#=> #<Class:0x007fe1e8b4f718>::Node
LinkedList::Node                    # inaccessible from outside
#=> NameError: uninitialized constant LinkedList::Node
LinkedList.const_get('Node')        # still inaccessible
#=> NameError: uninitialized constant LinkedList::Node

当然你可以Node访问

LinkedList.singleton_class::Node
#=> #<Class:0x007fe1e8b4f718>::Node

它也可以在LinkedList的单例类常量中使用:

LinkedList.singleton_class.constants
#=> [:Node, :DelegationError, :RUBY_RESERVED_WORDS, :Concerning]

我通常使用private_constant,但这是另一种开设私人课程的方式。

于 2016-09-27T07:17:00.380 回答