24 Jan 2016
V Ruby je programovací jazyk, definované metody přicházejí ve dvou variantách: metody instance a metody třídy. Metody Instance jsou k dispozici po inicializaci objektu, vytvoření instance. Metody třídy, na druhou stranu, jsou k dispozici bez vytvoření instance třídy, na které jsou definovány.
Ruby metody se mohou lišit ve viditelnosti. Veřejné metody jsou dostupné v jakémkoli kontextu, zatímco dostupnost soukromých metod je omezena v instanci třídy a jejích potomků. Třetí rozsah viditelnosti, chráněný, se chová podobně jako soukromé metody, ale chráněné metody mohou být volány jinými instancemi stejné třídy.
Pro rychlé zopakování, veřejné a soukromé instance, metody vypadat takto:
class Dog def do_trick bark end private def bark puts 'woof woof' endend
Když veřejnost je volána metoda:
> dog = Dog.new> dog.do_trick# => woof woof
A soukromé metody:
> dog = Dog.new> dog.bark# => NoMethodError: private method `bark' called for <Dog>
metody soukromé třídy nemusí být tak běžné jako metody soukromé instance, ale stále mají své místo. Například metoda třídy může vyžadovat interní pomocné metody k dokončení své funkce. Ať už je důvod jakýkoli, definování metod soukromé třídy má hodnotu, ale není vždy intuitivní.
tento příklad Dog
třída musí udržovat seznam tricks
, který bude použit v rámci jiných metod veřejné třídy. Tento seznam by neměl být přístupný žádnému volajícímu mimo třídu Dog
.
špatně
první zkoušku v psaní na soukromé tricks
metoda by mohla vypadat:
class Dog private def self.tricks endend
Nicméně, při testování viditelnosti tricks
metoda:
> Dog.tricks# =>
Uh oh, ne, chyba byla vyvolána což naznačuje, že privátní metoda byla volána, tato metoda je zcela veřejné.
proč?
důvod, proč výše uvedený kód nevytvořil soukromou metodu, souvisí s hierarchií objektů Ruby, interakcemi mezi interními třídami, instancemi těchto tříd a eigenclasses. Podrobný zápis o tom, jak Ruby objekty pracovat s sebou lze nalézt v předchozím příspěvku.
při definování metod ve třídě jsou výchozí kontext a kontext zavedený deklarací metody self.
odlišné.
rozsah soukromé metody nelze použít výše uvedeným způsobem, protože nezpracovává změnu kontextu mezi metodami definovanými na třídě Dog
a definovanými v kontextu self
.
jaké jsou tedy alternativy?
třída << vlastní
jedním z alternativních způsobů, jak definovat metody třídy na objektu, je použití syntaxe class << self
. Tato syntaxe otevře eigenclass pro dodaný argument. V tomto příkladu self
ve třídě Dog
otevře eigenclass Dog's
.
class Dog class << self private def tricks end endend
jedna věc, kterou je třeba poznamenat, je, že při definování metod, jako je tato, se deklarace změnila z def self.tricks
na jednoduše def tricks
.
nyní je zachován soukromý rozsah a je dosaženo očekávaného chování:
> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
moduly
moduly v ruby jsou kolekce metod a konstant. Tyto sbírky lze použít jako nástroje pro zapouzdření nebo, v tomto případě, alternativy k definování metod veřejné a soukromé třídy.
když třída extends
modul, všechny metody v rámci tohoto modulu se stanou třídními metodami ve třídě předmětu*. Tento vzor lze použít k definování metody tricks
na Dog
.
* Poznámka: To se týká jenom metody definované v „typický smysl“ všechny def self.
nebo def Dog.
metoda definice v modulu se automaticky stal metody třídy stejným způsobem, když extended
.
class Dog module ClassMethods private def tricks end end extend ClassMethodsend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
výhodou tohoto přístupu je čitelnost. Modul s názvem ClassMethods
, který je obsažen a tedy zapouzdřen třídou Dog
, je jasným domovem pro všechny požadované třídní metody.
modifikátory viditelnosti jako private
se chovají odpovídajícím způsobem a jednoduchý extend
ve spodní části Definice modulu to vše spojuje.
private_class_method
třetím přístupem je použití vestavěné metody Module#private_class_method
. Účelem této metody je změnit viditelnost existujících metod třídy.
na Rozdíl od dalších dvou řešení, tohle nevyžaduje jiný styl způsob definice z nesprávné řešení:
class Dog def self.tricks end private_class_method :tricksend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
Tato metoda může být také v lemované během class‘ definici metody:
class Dog private_class_method def self.tricks endend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
Pokud jeden metody třídy musí být soukromé a ukládání řádků je velmi důležité, že tento styl by mohl být použitelný; ale určitě obětuje úroveň čitelnosti.
hlavní síla private_class_method
je jeho explicitnost. Na rozdíl od ostatních přístupů tento nevyžaduje speciální definici modulu nebo přepínání kontextu definice metody.
další čtení
výše uvedená řešení dostanou práci, ale nemusí odpovídat na přetrvávající otázky o tom, proč věci fungují tak, jak fungují. Několik skvělých článků na ruby eigenclass a Matz myšlenky na Ruby metoda design by měl pomoci malovat výstižnější obrázek, proč Ruby soukromé metody třídy definice je složitá.