Как реализовать закрытый внутренний класс в Ruby
Исходя из Java, я пытаюсь реализовать LinkedList в Ruby. Обычный способ реализовать это в Java - это класс LinkedList и закрытый внутренний класс Node с каждым объектом LinkedList в качестве объекта Node.
class LinkedList
private
class Node
attr_accessor :val, :next
end
end
Я не хочу подвергать класс Node внешнему миру. Однако с этой настройкой в Ruby я могу получить доступ к частному объекту класса Node вне класса LinkedList, используя это -
node = LinkedList::Node.new
Я знаю, что в Ruby 1.9 мы можем использовать метод private_constant для обозначения Node как частной константы. Но мне интересно, если это правильный путь для достижения этой цели? Кроме того, почему я могу создавать объекты Node вне класса LinkedList, даже если он объявлен как закрытый?
2 ответа
Почему я могу создавать объекты Node вне класса LinkedList, даже если он объявлен как закрытый?
Потому что в рубиновых константах игнорируются "обычные" модификаторы видимости. Они всегда общедоступны, независимо от того, в каком разделе они находятся. Чтобы сделать их приватными, используйте 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
Я знаю, что ответа Серхио более чем достаточно, но я просто отвечаю на вопрос:
Как реализовать закрытый внутренний класс в 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
, но это еще один способ иметь закрытый класс.