24 Jan 2016
a Ruby programozási nyelvben a definiált metódusok két változatban léteznek: példány metódusok és osztály metódusok. A példánymódszerek az objektum inicializálása után állnak rendelkezésre, létrehozva egy példányt. Osztály metódusok, másrészről, rendelkezésre állnak anélkül, hogy létrehoznák annak az osztálynak a példányát, amelyen meg vannak határozva.
a Ruby módszerek láthatósága változhat. A nyilvános metódusok bármilyen kontextusban elérhetők, míg a privát metódusok elérhetősége korlátozott az osztály és leszármazottai példányán belül. A harmadik láthatósági hatókör, védett, hasonlóan viselkedik, mint a magán metódusok, de a védett metódusokat ugyanazon osztály más példányai is meghívhatják.
a gyors frissítéshez a nyilvános és a privát példány metódusai így néznek ki:
class Dog def do_trick bark end private def bark puts 'woof woof' endend
amikor a nyilvános módszert hívják:
> dog = Dog.new> dog.do_trick# => woof woof
a privát módszer:
> dog = Dog.new> dog.bark# => NoMethodError: private method `bark' called for <Dog>
lehet, hogy a privát osztály metódusok nem olyan gyakoriak, mint a privát példány metódusok, de még mindig megvan a helyük. Például egy osztály metódushoz belső segítő metódusokra lehet szükség a funkció befejezéséhez. Bármi is legyen az oka, a magánosztály módszereinek meghatározása értékes, de nem mindig intuitív.
ez a példa Dog
osztálynak fenn kell tartania a tricks
listát, amelyet a többi nyilvános osztály metódusán belül használnak. Ez a lista nem lehet elérhető a Dog
osztályon kívüli hívók számára.
a rossz út
az első lépés a privát tricks
módszer írásakor úgy nézhet ki, mint:
class Dog private def self.tricks endend
a tricks
módszer láthatóságának tesztelésekor azonban:
> Dog.tricks# =>
Uh oh, nem volt hiba, jelezve, hogy egy privát módszert hívtak, ez a módszer teljesen nyilvános.
miért?
annak oka, hogy a fenti kód nem hozott létre privát metódust, a Ruby objektumhierarchiájához, a belső osztályok közötti interakciókhoz, az osztályok példányaihoz és a sajátosztályokhoz kapcsolódik. Egy részletes írás arról, hogy Ruby tárgyai hogyan működnek egymással, megtalálható egy előző bejegyzésben.
egy osztály metódusainak meghatározásakor az alapértelmezett kontextus és a self.
metódus deklaráció által bevezetett kontextus elkülönül egymástól.
a privát metódus hatóköre nem használható a fenti módon, mivel nem kezeli a Dog
osztályban és a self
kontextusban definiált módszerek közötti kontextusváltást.
tehát mi az alternatíva?
class << self
az objektum osztály metódusainak meghatározásának egyik alternatív módja a class << self
szintaxis használata. Ez a szintaxis megnyit egy sajátosztályt a mellékelt argumentumhoz. Ebben a példában a self
a Dog
osztályon belül megnyitja a Dog's
sajátosztályt.
class Dog class << self private def tricks end endend
egy dolgot meg kell jegyezni, hogy az ilyen módszerek meghatározásakor a deklaráció def self.tricks
– ről egyszerűen def tricks
– re változott.
most a magán hatókör megmarad, és a várható viselkedés megvalósul:
> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
modulok
a ruby modulok módszerek és állandók gyűjteményei. Ezek a gyűjtemények felhasználhatók kapszulázási eszközként, vagy ebben az esetben alternatívák a nyilvános és a privát osztály metódusainak meghatározására.
amikor egy osztály extends
a modul, az összes metódusok belül modul lesz osztály módszerek a tárgy osztály*. Ez a minta használható a tricks
módszer meghatározására Dog
– en.
* Megjegyzés: Ez csak a “tipikus értelemben” definiált módszerekre vonatkozik bármely def self.
vagy def Dog.
metódusdefiníciók egy modulban nem válnak automatikusan osztály metódusokká ugyanúgy, amikor extended
.
class Dog module ClassMethods private def tricks end end extend ClassMethodsend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
ennek a megközelítésnek az előnye az olvashatóság. A ClassMethods
nevű modul, amelyet a Dog
osztály tartalmaz és így kapszuláz, az összes kívánt osztálymódszer tiszta otthona.
a láthatósági módosítók, mint például az private
ennek megfelelően viselkednek, és a moduldefiníció alján található egyszerű extend
összehozza az egészet.
private_class_method
a harmadik megközelítés a beépített módszer használata Module#private_class_method
. Ennek a módszernek az a célja, hogy megváltoztassa a meglévő osztálymódszerek láthatóságát.
a másik két megoldástól eltérően ez nem igényel más módszermeghatározási stílust, mint a helytelen megoldás:
class Dog def self.tricks end private_class_method :tricksend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
ez a módszer az osztály metódus-meghatározása során is beilleszthető:
class Dog private_class_method def self.tricks endend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
ha egy osztály metódusnak privátnak kell lennie, és a sorok mentése nagyon fontos, akkor ez a stílus alkalmazható; de, minden bizonnyal feláldozza az olvashatóság szintjét.
a private_class_method
fő erőssége az explicitsége. A többi megközelítéstől eltérően ez nem igényel speciális moduldefiníciót vagy módszerdefiníciós kontextusváltást.
további olvasmányok
a fent említett megoldások elvégzik a munkát, de nem biztos, hogy megválaszolják az elhúzódó kérdéseket arról, hogy miért működnek a dolgok úgy, ahogy. Néhány nagyszerű cikk a ruby eigenclass – ról és Matz gondolatairól a Ruby method design – ról segíthet egy tömörebb képet festeni arról, hogy miért összetett A Ruby private class method definíciója.