Ruby Private Class methoden

24 Jan 2016

in de Ruby programmeertaal, gedefinieerde methoden komen in twee varianten: instantie methoden en klasse methoden. Instance methoden zijn beschikbaar nadat een object is geïnitialiseerd, het maken van een instantie. Class methoden, aan de andere kant, zijn beschikbaar zonder het creëren van een instantie van de klasse waarop ze zijn gedefinieerd.

Ruby-methoden kunnen variëren in zichtbaarheid. Publieke methoden zijn beschikbaar in elke context, terwijl de beschikbaarheid van private methoden beperkt is binnen de instantie van een klasse en zijn nakomelingen. Een derde zichtbaarheidsbereik, protected, gedraagt zich op dezelfde manier als private methoden, maar beschermde methoden kunnen worden aangeroepen door andere instanties van dezelfde klasse.

voor een snelle opfriscursus zien publieke en private instantiemethoden er als volgt uit:

class Dog def do_trick bark end private def bark puts 'woof woof' endend

wanneer de publieke methode wordt genoemd:

> dog = Dog.new> dog.do_trick# => woof woof

en de private methode:

> dog = Dog.new> dog.bark# => NoMethodError: private method `bark' called for <Dog>

Private class methoden zijn misschien niet zo gebruikelijk als private instance methoden, maar ze hebben nog steeds hun plaats. Bijvoorbeeld, een klasse methode kan interne helper methoden vereisen om zijn functie te voltooien. Wat de reden ook is, het definiëren van private class methoden heeft waarde, maar is niet altijd intuïtief.

dit voorbeeld Dog klasse moet een lijst van tricks bijhouden die zal worden gebruikt binnen de andere openbare klasse methoden. Deze lijst mag niet toegankelijk zijn voor bellers buiten de klasse Dog.

op de verkeerde manier

een eerste stap bij het schrijven van de private tricks methode zou er zo uit kunnen zien:

class Dog private def self.tricks endend

bij het testen van de zichtbaarheid van de tricks – methode:

> Dog.tricks# => 

Uh oh, geen fout werd gegooid met vermelding van een dat een privé methode werd genoemd, deze methode is volledig openbaar.

waarom?

de reden dat bovenstaande code geen privémethode produceerde, heeft te maken met Ruby ‘ s objecthiërarchie, interacties tussen interne klassen, instanties van die klassen en eigenklassen. Een gedetailleerd artikel over hoe Ruby ‘ s objecten met elkaar werken is te vinden in een vorige post.

wanneer methoden in een klasse worden gedefinieerd, zijn de standaardcontext en de context die door de self. methodedeclaratie wordt geïntroduceerd, verschillend.

de private methode scope kan niet op de bovenstaande manier worden gebruikt omdat het niet de context verandering tussen methoden gedefinieerd op de Dog klasse en gedefinieerd binnen self context behandelt.

wat zijn de alternatieven?

klasse << zelf

een andere manier om klassenmethoden op een object te definiëren is door de syntaxis class << self te gebruiken. Deze syntaxis opent een eigenklasse voor het gegeven argument. In dit voorbeeld zal self binnen de klasse Dog de eigklasse Dog's openen.

class Dog class << self private def tricks end endend

een ding om op te merken is dat bij het definiëren van methoden als deze, de declaratie is veranderd van def self.tricks naar gewoon def tricks.

nu wordt de particuliere ruimte behouden en wordt verwacht gedrag bereikt:

> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Modules

Modules in ruby zijn verzamelingen van methoden en constanten. Deze collecties kunnen worden gebruikt als inkapseling tools of, in dit geval, alternatieven voor het definiëren van publieke en private klasse methoden.

wanneer een klasse extends een module, alle methoden binnen die module worden Klasse methoden op de onderwerpklasse*. Dit patroon kan worden gebruikt om de tricks methode op Dogte definiëren.

* Noot: Dit heeft alleen betrekking op methoden die in “typische zin” zijn gedefinieerd.elke def self. of def Dog. methodedefinities in een module worden niet automatisch op dezelfde manier klassemethoden wanneer extended.

class Dog module ClassMethods private def tricks end end extend ClassMethodsend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

een voordeel van deze aanpak is leesbaarheid. De module genaamd ClassMethods, die is opgenomen en dus ingekapseld door de klasse Dog, is de clear home voor alle gewenste klasse methoden.

zichtbaarheid modifiers zoals private gedragen zich dienovereenkomstig en een eenvoudige extend aan de onderkant van de module definitie brengt het allemaal samen.

private_class_method

een derde methode is het gebruik van de ingebouwde methode Module#private_class_method. Het doel van deze methode is om de zichtbaarheid van bestaande klassemethoden te veranderen.

in tegenstelling tot de andere twee oplossingen vereist deze geen andere methode-definitie dan de onjuiste oplossing:

class Dog def self.tricks end private_class_method :tricksend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

deze methode kan ook worden in-lined tijdens de klasse ‘ methode definitie:

class Dog private_class_method def self.tricks endend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

als een single class methode privé moet zijn en het opslaan van regels erg belangrijk is, kan deze stijl van toepassing zijn; maar, het zeker offert een niveau van leesbaarheid.

een belangrijke sterkte van private_class_method is de expliciteit ervan. In tegenstelling tot de andere benaderingen, vereist deze geen speciale module definitie of methode definitie context switching.

verder lezen

de bovengenoemde oplossingen zullen de klus klaren, maar kunnen geen antwoord geven op aanhoudende vragen over waarom dingen werken zoals ze doen. Een paar grote artikelen over de ruby eigenklas en Matz ’s gedachten over Ruby methode ontwerp moet helpen schilderen een beknopter beeld van waarom Ruby’ s private class methode definitie is complex.

You might also like

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.