Il n'y a vraiment pas d'équivalent en construction Ruby.
Cependant, il semble que vous faites l'une des erreurs de portage classique: vous avez une solution en langage A et essayer de traduire en langage B, quand ce que vous devriez vraiment faire est de déterminer le problème et puis comprendre comment le résoudre dans la langue B.
Je ne peux pas vraiment être sûr quel est le problème que vous essayez de résoudre à partir de ce petit code codes, mais voici un idée possible pour la mettre en œuvre en 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
Voici une autre:
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
(La différence est que le premier exemple est paresseux, il initialise que la variable d'instance lorsque le lecteur d'attribut correspondant est d'abord appelé. Le second les initialise dès que le corps de la classe est exécuté, même s'ils ne sont jamais nécessaires, tout comme la version Java.)
Reprenons quelques concepts ici. Dans Ruby, comme dans tous les autres langages "appropriés" (pour diverses définitions du langage "propre"), l'état (variables d'instance, champs, propriétés, emplacements, attributs, peu importe comment vous les appelez) est toujours privé. Il n'y a aucun pour y accéder de l'extérieur. La seule façon de communiquer avec un objet est de lui envoyer des messages. [Note: Chaque fois que j'écris quelque chose comme "pas d'accord", "toujours", "la seule façon" etc., cela ne signifie en réalité "aucun moyen, sauf pour la réflexion". En d'autres termes: dans Ruby, les variables sont toujours privées, la seule façon d'y accéder est par une méthode getter et/ou setter, ou, comme elles le sont appelé dans Ruby, un lecteur d'attributs et/ou écrivain.
Maintenant, je continue à écrire sur variables d'instance, mais dans l'exemple Java, nous avons champs statiques, à savoir variables de classe. Eh bien, dans Ruby, contrairement à Java, les classes sont aussi des objets. Ce sont des instances de la classe Class
et ainsi, comme tout autre objet, ils peuvent avoir des variables d'instance. Donc, dans Ruby, l'équivalent d'une variable de classe est vraiment juste une variable d'instance standard qui appartient à un objet qui se trouve être une classe. Il existe également des variables de hiérarchie de classes, notées avec un double au signe @@sigil
.Celles-ci sont vraiment étranges, et vous devriez probablement les ignorer.Les variables de hiérarchie de classe sont partagées dans toute la hiérarchie de classe, à savoir la classe à laquelle elles appartiennent , toutes ses sous-classes et leurs sous-classes et leurs sous-classes ... et aussi toutes les instances de toutes ces classes.En fait, elles ressemblent plus à des variables globales qu'à des variables de classe.Ils devraient vraiment s'appeler $$var
au lieu de @@var
, puisqu'ils sont beaucoup plus étroitement liés aux variables globales plutôt qu'aux variables d'instance, ils ne sont pas totalement inutiles mais très rarement utiles.)
Donc, nous avons couvert la partie "champ" (champ Java == R uby instance variable), nous avons couvert les parties "public" et "private" (dans Ruby, les variables d'instance sont toujours privées, si vous voulez les rendre publiques, utilisez une méthode publique getter/setter) et nous avons couvert "partie (Java static field == variable d'instance de la classe Ruby).Qu'en est-il de la partie "finale"? En Java, "final" est juste une façon amusante d'orthographe "const", que les concepteurs ont évité car le mot-clé const
dans des langages comme C et C++ est subtilement cassé et ils ne voulaient pas confondre les gens. Ruby a ont des constantes (notées en commençant par une lettre majuscule). Malheureusement, ils ne sont pas vraiment constants, car essayer de les modifier, tout en générant un avertissement, fonctionne réellement. Donc, ils sont plus d'une convention qu'une règle imposée par un compilateur. Cependant, la restriction la plus importante des constantes est qu'elles sont toujours publiques.
Ainsi, les constantes sont presque parfaits: ils ne peuvent pas être modifiés (bien, ils ne doivent pas être modifiés), à savoir qu'ils sont final
, ils appartiennent à une classe (ou module), à savoir qu'ils sont static
. Mais ils sont toujours public
, donc malheureusement, ils ne peuvent pas être utilisés pour modéliser les champs private static final
.
Et c'est exactement le point où la réflexion sur les problèmes au lieu de solutions intervient. Qu'est-ce que vous voulez? Vous voulez affirment que
- appartient à une classe,
- ne peut être lu pas écrit,
- est initialisées une fois
- peut être privé ou public.
Vous pouvez réaliser tout cela, mais d'une manière complètement différente de celle de Java:
- ne fournissent pas une instance de classe variable de
- une méthode setter, seul un getter
- utilisation l'affectation composée
||=
de Ruby pour assigner une seule fois
- getter
La seule chose dont vous avez à vous soucier, c'est que vous n'attribuez pas à @my_public_device
n'importe où, ou mieux encore, n'y accédez pas du tout. Utilisez toujours la méthode getter.
Oui, ce est un trou dans l'implémentation. Ruby est souvent appelé un "langage adulte" ou un "langage adulte consentant", ce qui signifie qu'au lieu d'imposer certaines choses au compilateur, il suffit de les mettre dans la documentation et de croire que les autres développeurs ont appris que toucher les autres les soldats des gens est rude ...
un totalement approche différente à la vie privée est celle qui est utilisée dans les langages fonctionnels: les fermetures d'utilisation. Les fermetures sont des blocs de code qui ferment sur leur environnement lexical, même après que l'environnement lexical est hors de portée. Cette méthode de mise en œuvre d'un état privé est très populaire dans Scheme, mais a récemment été popularisée par Douglas Crockford et al. pour JavaScript. Voici un exemple de 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
Notez la différence subtile mais importante pour les versions en haut de ma réponse: le manque de @
Sigil.Ici, nous créons variables locales, pas instance variables. Dès que le corps de la classe se termine, ces variables locales tombent hors de portée et ne peuvent plus jamais être accessibles. Seuls les deux blocs qui définissent les deux méthodes getter ont toujours accès à eux, car ils ferment sur le corps de la classe. Maintenant, ils sont vraiment privé et ils sont final
, parce que la seule chose dans l'ensemble du programme qui a toujours accès à eux est une pure méthode getter.
Ceci n'est probablement pas idiomatique Ruby, mais pour toute personne ayant un arrière-plan Lisp ou JavaScript, il devrait être assez clair. C'est aussi très élégant.
AFAIK il n'y a pas des constantes réelles (finales) en Ruby –
mais on peut utiliser 'SOME_CONSTANT.freeze' pour faire un objet immuable – clyfe
Que diriez-vous cette solution http://stackoverflow.com/a/18168745/665967 –