В Ruby действительно нет эквивалентной конструкции.
Однако похоже, что вы совершаете одну из классических ошибок переноса: у вас есть решение на языке А, и вы пытаетесь перевести его на язык Б, тогда как на самом деле вам нужно выяснить задачу, а затем выяснить, как решить ее на языке Б.
Я не могу точно сказать, какую проблему вы пытаетесь решить с помощью этого небольшого фрагмента кода, но вот одна возможная идея, как реализовать это в 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, как и в любом другом «правильном» (для различных определений «правильного») объектно-ориентированном языке, состояние (переменные экземпляра, поля, свойства, слоты, атрибуты, как бы вы их ни называли) всегда< /em> частный. Доступ к ним извне невозможен. Единственный способ общаться с объектом — отправлять ему сообщения.
[Примечание: Всякий раз, когда я пишу что-то вроде «ни за что», «всегда», «единственный способ» и т. д., это на самом деле не означает «ни за что, кроме как для размышления». В данном конкретном случае, например, Object#instance_variable_set
.]
Другими словами: в Ruby переменные всегда являются приватными, единственный способ получить к ним доступ — использовать метод получения и/или установки, или, как они называются в Ruby, считыватель и/или писатель атрибутов.
Теперь я продолжаю писать о переменных экземпляра, но в примере Java у нас есть статические поля, то есть переменные класса. Что ж, в Ruby, в отличие от Java, классы тоже являются объектами. Они являются экземплярами класса Class
, поэтому, как и любой другой объект, они могут иметь переменные экземпляра. Таким образом, в Ruby эквивалентом переменной класса является стандартная переменная экземпляра, которая принадлежит объекту, который просто является классом.
(Есть также переменные иерархии классов, обозначенные двойным знаком @@sigil
. Это действительно странно, и вам, вероятно, следует просто игнорировать их. Переменные иерархии классов являются общими для всей иерархии классов, то есть класса, к которому они принадлежат, всех его подклассов. и их подклассы и их подклассы ... а также все экземпляры всех этих классов. На самом деле, они больше похожи на глобальные переменные, чем на переменные класса. Их действительно следует называть $$var
вместо @@var
, поскольку они гораздо более тесно связаны с глобальными переменные, чем переменные экземпляра. Они не совсем бесполезны, но очень редко полезны.)
Итак, мы рассмотрели часть «поля» (поле Java == переменная экземпляра Ruby), мы рассмотрели «общедоступную» и «частную» части (в Ruby переменные экземпляра всегда являются частными, если вы хотите сделать их общедоступными, использовать общедоступный метод получения/установки), и мы рассмотрели «статическую» часть (статическое поле Java == переменная экземпляра класса Ruby). А как насчет "заключительной" части?
В Java «final» — это просто забавный способ написания «const», которого дизайнеры избегали, потому что ключевое слово const
в таких языках, как C и C++, немного нарушено, и они не хотели запутать людей. В Ruby действительно есть константы (обозначаются с заглавной буквы). К сожалению, на самом деле они не являются постоянными, потому что попытка изменить их, генерируя предупреждение, на самом деле работает. Таким образом, они являются скорее соглашением, чем правилом, навязанным компилятором. Однако более важным ограничением констант является то, что они всегда общедоступны.
Итак, константы почти идеальны: их нельзя изменить (ну, не следует изменять), т.е. они final
, они принадлежат классу (или модулю), т.е. они static
. Но они всегда public
, поэтому, к сожалению, их нельзя использовать для моделирования private static final
полей.
И это именно тот момент, когда нужно думать о проблемах, а не о решениях. Чего вы хотите? Вы хотите заявить, что
- принадлежит классу,
- можно только читать, а не писать,
- инициализируется только один раз и
- может быть как частным, так и публичным.
Вы можете добиться всего этого, но совершенно другим способом, чем в Java:
- переменная экземпляра класса
- не предоставляйте метод установки, только метод получения
- используйте составное назначение Ruby
||=
, чтобы назначить только один раз
- геттерный метод
Единственное, о чем вам нужно беспокоиться, это то, что вы нигде не назначаете @my_public_device
, или, что еще лучше, вообще не получаете к нему доступ. Всегда используйте метод получения.
Да, это это дыра в реализации. Ruby часто называют «языком взрослых» или «языком взрослых с согласия», что означает, что вместо того, чтобы компилятор навязывал определенные вещи, вы просто помещаете их в документацию и просто верите, что ваши коллеги-разработчики усвоили, что касаться других личные сообщения людей грубы...
Совершенно другой подход к конфиденциальности используется в функциональных языках: используйте замыкания. Замыкания — это блоки кода, которые закрываются в своем лексическом окружении даже после того, как это лексическое окружение выходит за рамки. Этот метод реализации частного состояния очень популярен в Scheme, но недавно его также популяризировали Douglas Crockford et al. для JavaScript. Вот пример на Руби:
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, это должно быть достаточно ясно. Это также очень элегантно.
person
Jörg W Mittag
schedule
14.03.2010
SOME_CONSTANT.freeze
, чтобы сделать объект неизменным - person clyfe   schedule 14.03.2010