Metode de clasă privată Ruby

24 Jan 2016

în limbajul de programare Ruby, metodele definite vin în două variante: metode de instanță și metode de clasă. Metodele de instanță sunt disponibile după ce un obiect a fost inițializat, creând o instanță. Metodele de clasă, pe de altă parte, sunt disponibile fără a crea o instanță a clasei pe care sunt definite.

metodele Ruby pot varia în vizibilitate. Metodele publice sunt disponibile în orice context, în timp ce disponibilitatea metodelor private este restricționată în instanța unei clase și a descendenților acesteia. Un al treilea domeniu de vizibilitate, protejat, se comportă similar cu metodele private, dar metodele protejate pot fi numite de alte instanțe din aceeași clasă.

pentru o reîmprospătare rapidă, metodele de instanță publice și private arată astfel:

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

când se numește metoda publică:

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

și metoda privată:

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

metodele de clasă privată s-ar putea să nu fie la fel de comune ca metodele de instanță privată, dar au totuși locul lor. De exemplu, o metodă de clasă poate necesita metode de ajutor intern pentru a-și finaliza funcția. Oricare ar fi motivul, definirea metodelor de clasă privată are valoare, dar nu este întotdeauna intuitivă.

acest exemplu Dog clasă trebuie să mențină o listă de tricks care vor fi utilizate în cadrul celorlalte metode de clasă publică. Această listă nu ar trebui să fie accesibilă niciunui apelant din afara clasei Dog.

în mod greșit

o primă trecere la scrierea metodei private tricks ar putea arăta:

class Dog private def self.tricks endend

cu toate acestea, atunci când se testează vizibilitatea metodei tricks :

> Dog.tricks# => 

Uh oh, nici o eroare a fost aruncat indicând o că o metodă privată a fost numit, această metodă este complet publică.

de ce?

motivul pentru care codul de mai sus nu a produs o metodă privată are legătură cu ierarhia obiectelor lui Ruby, interacțiunile dintre clasele interne, instanțele acelor clase și clasele proprii. O scriere detaliată despre modul în care obiectele lui Ruby funcționează între ele poate fi găsită într-o postare anterioară.

la definirea metodelor dintr-o clasă, contextul implicit și contextul introdus de declarația metodei self. sunt distincte.

domeniul metodei private nu poate fi utilizat în modul de mai sus, deoarece nu tratează schimbarea contextului între metodele definite în clasa Dog și definite în contextul self.

deci, care sunt alternativele?

class< < self

o modalitate alternativă de a defini metodele de clasă pe un obiect este de a utiliza sintaxa class << self. Această sintaxă deschide o clasă proprie pentru argumentul furnizat. În acest exemplu, self în cadrul Dog clasa va deschide Dog's eigenclass.

class Dog class << self private def tricks end endend

un lucru de remarcat este că atunci când se definesc metode ca aceasta, declarația s-a schimbat de la def self.tricks la pur și simplu def tricks.

acum, domeniul privat este păstrat și comportamentul așteptat este atins:

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

module

Module în ruby sunt colecții de metode și constante. Aceste colecții pot fi utilizate ca instrumente de încapsulare sau, în acest caz, alternative la definirea metodelor de clasă publică și privată.

când o clasă extends un modul, toate metodele din acel modul devin metode de clasă pe clasa subiect*. Acest model poate fi folosit pentru a defini metoda trickspe Dog.

* notă: Aceasta se referă numai la metodele definite într-un „sens tipic” orice definiție a metodei def self. sau def Dog. dintr-un modul nu devine automat metode de clasă în același mod atunci când extended.

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

un beneficiu al acestei abordări este lizibilitatea. Modulul numit ClassMethods, care este conținut și astfel încapsulat de clasa Dog, este casa clară pentru toate metodele de clasă dorite.

modificatori de vizibilitate, cum ar fi private se comportă în consecință și un simplu extend în partea de jos a definiției modulului aduce totul împreună.

private_class_method

o a treia abordare este de a utiliza construit în metoda Module#private_class_method. Scopul acestei metode este de a schimba vizibilitatea metodelor de clasă existente.

spre deosebire de celelalte două soluții, aceasta nu necesită un stil diferit de definire a metodei de soluția incorectă:

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

această metodă poate fi, de asemenea, căptușită în timpul definiției metodei clasei:

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

dacă o singură metodă de clasă trebuie să fie privată și salvarea liniilor este foarte importantă, acest stil ar putea fi aplicabil; dar, cu siguranță, sacrifică un nivel de lizibilitate.

o forță majoră a private_class_method este explicitatea sa. Spre deosebire de celelalte abordări, aceasta nu necesită o definiție specială a modulului sau comutarea contextului de definiție a metodei.

lecturi suplimentare

soluțiile menționate mai sus vor face treaba, dar s-ar putea să nu răspundă la întrebări persistente despre motivul pentru care lucrurile funcționează așa cum o fac. Câteva articole grozave despre ruby eigenclass și gândurile lui Matz despre proiectarea metodei Ruby ar trebui să ajute la pictarea unei imagini mai concise a motivului pentru care definiția metodei clasei private a lui Ruby este complexă.

You might also like

Lasă un răspuns

Adresa ta de email nu va fi publicată.