В 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 переменные всегда являются закрытыми, единственный способ получить к ним доступ через метод получения и / или установки, или, поскольку они вызываются в Ruby, считывателе атрибутов и / или модуле записи.
Теперь я продолжаю писать о переменных экземпляра , но в примере с Java у нас есть статические поля , то есть класс переменных.В Ruby, в отличие от Java, классы тоже являются объектами.Они являются экземплярами класса Class
, поэтому, как и любой другой объект, они могут иметь переменные экземпляра.Таким образом, в Ruby эквивалент переменной класса на самом деле представляет собой стандартную переменную экземпляра, которая принадлежит объекту, который просто является классом.
(Существуют также переменные иерархии классов, обозначаемые двойнымзнак @@sigil
. Это действительно странно, и вы, вероятно, должны просто игнорировать их. Переменные иерархии классов совместно используются всей иерархией классов, то есть классу, к которому они принадлежат, всем его подклассам и их подклассам и их подклассам ... а такжевсе экземпляры всех этих классов. На самом деле, они больше похожи на глобальные переменные, чем на переменные класса. Они должны называться $$var
вместо @@var
, поскольку они гораздо более тесно связаны с глобальными переменными, чем переменные экземпляра.не совсем бесполезно, но очень редко полезно.)
Итак, мы рассмотрели часть «поля» (поле Java == переменная экземпляра Ruby), мы рассмотрели «открытую» и «закрытую» части (вRuby, переменные экземпляра всегда закрыты, если вы хотите сделатьОни являются общедоступными, используйте общедоступный метод получения / установки), и мы рассмотрели «статическую» часть (статическое поле Java == переменная экземпляра класса Ruby).А как насчет «финальной» части?
В Java «финальная» - это просто забавный способ написания «const», которого дизайнеры избегают, потому что ключевое слово const
в таких языках, как C и C ++, слегка ломаетсяи они не хотели путать людей.Ruby имеет константы (обозначается с заглавной буквы).К сожалению, они не являются на самом деле постоянными, потому что попытка изменить их, генерируя предупреждение, на самом деле работает.Таким образом, они являются скорее соглашением, чем правилом, применяемым компилятором.Однако более важным ограничением констант является то, что они всегда являются публичными.
Итак, константы почти идеальны: они не могут быть изменены (ну, они не должны быть изменены), то есть они final
, они принадлежат классу (или модулю), то есть они являются static
. Но они всегда public
, поэтому, к сожалению, их нельзя использовать для моделирования private static final
полей.
И это как раз тот момент, когда приходит думать о проблемах, а не о решениях. Чего вы хотите? Вы хотите заявить, что
- принадлежит классу,
- можно прочитать только не написано,
- инициализируется только один раз и
- может быть частным или общедоступным.
Вы можете достичь всего этого, но совершенно иначе, чем в Java:
- переменная экземпляра класса
- не предоставляют метод установки, только метод получения
- используйте составное назначение Ruby
||=
для назначения только один раз
- метод получения
Единственное, о чем вам нужно беспокоиться, это то, что вы нигде не назначаете @my_public_device
, или, что еще лучше, вообще не обращаетесь к нему. Всегда используйте метод получения.
Да, - это дыра в реализации. Ruby часто называют «языком взрослого» или «языком взрослых для согласия», что означает, что вместо того, чтобы компилятор предписывал определенные вещи, вы просто помещаете их в документацию и просто полагаете, что ваши коллеги-разработчики узнали, что касаются других рядовые люди грубы ...
Совершенно другой подход к конфиденциальности - тот, который используется в функциональных языках: используйте замыкания. Замыкания - это блоки кода, которые закрываются в своей лексической среде, даже после того, как эта лексическая среда вышла из области видимости. Этот метод реализации частного государства очень популярен в Схеме, но в последнее время он также популяризируется Дугласом Крокфордом и соавт. для 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
Обратите внимание на тонкое, но важное отличие версий в верхней части моего ответа: отсутствие символа @
. Здесь мы создаем локальные переменные, а не экземпляр переменные. Как только тело класса заканчивается, эти локальные переменные выходят из области видимости и больше никогда не будут доступны. Только два блока, которые определяют два метода-получателя, все еще имеют к ним доступ, потому что они закрывают тело класса. Теперь они на самом деле частные и они final
, потому что единственная вещь во всей программе, которая все еще имеет к ним доступ, это чистый метод получения .
Это, вероятно, не идиоматический Ruby, но для любого, кто имеет опыт работы с Lisp или JavaScript, это должно быть достаточно ясно. Это также очень элегантно.