Самая важная вещь, которую нужно осознать, это то, что класс не является чем-то особенным. Это просто объект. В соответствии с соглашением классы присваиваются константам, но ничто не говорит о том, что они имеют .
И поскольку классы - это просто объекты, как и любой другой объект, вы делаете их закрытыми так же, как и любой другой объект.
Вот возможности, которые я могу придумать в порядке увеличения приватности:
- Просто вложите их в пространство имен (то есть модуль). В Ruby обычно ожидается, что все модули и классы библиотеки живут в пространстве имен с тем же именем, что и библиотека (т.е.
my_awesome_library
& rarr; MyAwesomeLibrary
), но в целом все, что вложено в это пространство имен, считается частным. На самом деле, кроме Test::Unit::TestCase
, я не могу вспомнить ни одного примера трехуровневого глубокого пространства имен, которое, как ожидается, будет использоваться клиентским кодом.
- то же самое, что и 1., но назовите это чем-то очевидным, например
MyAwesomeLibrary::Internal::FfiStruct
- то же самое, что и 1. или 2., и пометьте его тегом
:nodoc:
RDoc.
- аналогично 3., но использует более современную систему документации, такую как YARD, которая фактически позволяет явно разметить частные API.
- Используйте метод вместо константы. Методы могут быть сделаны частными. (Ради согласованности, имя метода может начинаться с заглавной буквы, чтобы оно напоминало константу. Ничто не может предотвратить это, соглашение
snake_case
- это просто соглашение.)
- Используйте переменную экземпляра. Они всегда приватны. Обратите внимание, что как частные методы, так и переменные экземпляра могут быть легко доступны с помощью отражения.
send
, похоже, используется более широко, чем instance_variable_get
, поэтому я считаю, что переменные экземпляра имеют более высокий уровень конфиденциальности, чем методы.
- Действительно, единственный способ получить реальную конфиденциальность или инкапсуляцию - это использовать локальные переменные и замыкания. Однако обратите внимание, что это может помешать вам использовать синтаксис определения модуля, класса или метода Ruby, поскольку они создают новые области видимости. Во всех случаях, когда вам нужен доступ к классу, вы должны использовать
Module.new
, Class.new
или Module#define_method
.
Ex:.
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
И да, это только способ достижения истинного 100% сокрытия и инкапсуляции информации в Ruby.
Тем не менее, обычный способ Ruby состоит в том, чтобы просто задокументировать материал как частный (возможно, снизить его до уровня пространства имен) и довериться своим коллегам-разработчикам. В сообществе Ruby это иногда обобщается под лозунгом Python «Мы все взрослые по обоюдному согласию».