Ruby private Class metoder

24 Jan 2016

i Ruby programmeringssprog, definerede metoder findes i to varianter: instansmetoder og klassemetoder. Instansmetoder er tilgængelige, efter at et objekt er initialiseret, hvilket skaber en forekomst. Klassemetoder er derimod tilgængelige uden at oprette en forekomst af den klasse, de er defineret på.

Ruby metoder kan variere i synlighed. Offentlige metoder er tilgængelige i enhver sammenhæng, mens private metoders tilgængelighed er begrænset inden for forekomsten af en klasse og dens efterkommere. Et tredje synlighedsområde, beskyttet, opfører sig på samme måde som private metoder, men beskyttede metoder kan kaldes af andre tilfælde af samme klasse.

for en hurtig genopfriskning ser offentlige og private instansmetoder sådan ud:

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

når den offentlige metode kaldes:

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

den private metode:

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

Private klassemetoder er muligvis ikke så almindelige som private instansmetoder, men de har stadig deres plads. For eksempel kan en klassemetode kræve interne hjælpemetoder for at fuldføre sin funktion. Uanset årsagen har definition af private klassemetoder værdi, men er ikke altid intuitiv.

dette eksempel Dog klasse skal opretholde en liste over tricks, der vil blive brugt inden for de andre offentlige klassemetoder. Denne liste bør ikke være tilgængelig for opkaldere uden for Dog – klassen.

den forkerte måde

et første pass ved at skrive den private tricks metode kunne se ud:

class Dog private def self.tricks endend

men når man tester synligheden af tricks – metoden:

> Dog.tricks# => 

Uh åh, ingen fejl blev kastet indikerer en, at en privat metode blev kaldt, denne metode er helt offentlig.

hvorfor?

årsagen til, at ovenstående kode ikke producerede en privat metode, har at gøre med Rubys objekthierarki, interaktioner mellem interne klasser, forekomster af disse klasser og egenklasser. En detaljeret skrive op om, hvordan Ruby objekter arbejde med hinanden kan findes i et tidligere indlæg.

når man definerer metoder i en klasse, er standardkonteksten og konteksten introduceret af self. metodedeklarationen forskellige.

det private metodeområde kan ikke bruges på ovenstående måde, da det ikke håndterer kontekstændringen mellem metoder defineret på Dog klassen og defineret inden for self kontekst.

så hvad er alternativerne?

klasse< < selv

en alternativ måde at definere klassemetoder på et objekt er at bruge syntaksen class << self. Denne syntaks åbner en egenklasse for det medfølgende argument. I dette eksempel åbner self inden for Dog klassen Dog's eigenclass.

class Dog class << self private def tricks end endend

en ting at bemærke er, at når man definerer metoder som denne, er erklæringen ændret fra def self.tricks Til simpelthen def tricks.

nu bevares det private omfang, og forventet adfærd opnås:

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

moduler

moduler i ruby er samlinger af metoder og konstanter. Disse samlinger kan bruges som indkapslingsværktøjer eller i dette tilfælde alternativer til at definere offentlige og private klassemetoder.

når en klasse extends et modul, bliver alle metoderne inden for dette modul klassemetoder på fagklassen*. Dette mønster kan bruges til at definere tricks – metoden på Dog.

*Bemærk: Dette vedrører kun metoder defineret i en “typisk forstand” enhver def self. eller def Dog. metodedefinitioner i et modul bliver ikke automatisk klassemetoder på samme måde, når extended.

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

en fordel ved denne tilgang er læsbarhed. Modulet med navnet ClassMethods, som er indeholdt og således indkapslet af Dog – klassen, er det klare hjem for alle ønskede klassemetoder.

Synlighedsmodifikatorer som private opfører sig i overensstemmelse hermed, og en simpel extend nederst i moduldefinitionen bringer det hele sammen.

private_class_method

en tredje tilgang er at bruge den indbyggede metode Module#private_class_method. Denne metodes formål er at ændre synligheden af eksisterende klassemetoder.

i modsætning til de to andre løsninger kræver denne ikke en anden stil af metodedefinition fra den forkerte løsning:

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

denne metode kan også være in-foret under klassen’ metode definition:

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

hvis en enkelt klassemetode skal være privat, og det er meget vigtigt at gemme linjer, denne stil kan være anvendelig; men det ofrer bestemt et niveau af læsbarhed.

en stor styrke på private_class_method er dens eksplicitness. I modsætning til de andre tilgange kræver denne ikke en særlig moduldefinition eller metodedefinition kontekstskift.

yderligere læsning

de førnævnte løsninger får jobbet gjort, men svarer muligvis ikke på langvarige spørgsmål om, hvorfor tingene fungerer som de gør. Et par gode artikler om ruby eigenclass og Matts tanker om Ruby method design skal hjælpe med at male et mere præcist billede af, hvorfor Rubys private class method definition er kompleks.

You might also like

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.