24 tammi 2016
Ruby-ohjelmointikielessä määriteltyjä menetelmiä on kaksi varianttia: instanssimenetelmät ja luokkamenetelmät. Instanssimenetelmät ovat käytettävissä olion alustamisen jälkeen, jolloin luodaan instanssi. Luokkamenetelmät taas ovat käytettävissä luomatta esiintymää siitä luokasta, johon ne on määritelty.
Ruby-menetelmien näkyvyys voi vaihdella. Julkiset menetelmät ovat käytettävissä kaikissa yhteyksissä, kun taas yksityisten menetelmien saatavuus on rajoitettu luokan ja sen jälkeläisten tapauksessa. Kolmas näkyvyysalue, suojattu, käyttäytyy samalla tavalla kuin yksityiset menetelmät, mutta suojattuja menetelmiä voidaan kutsua myös muilla saman luokan instansseilla.
nopeassa kertauksessa julkisen ja yksityisen instanssin menetelmät näyttävät tältä:
class Dog def do_trick bark end private def bark puts 'woof woof' endend
kun julkista menetelmää kutsutaan:
> dog = Dog.new> dog.do_trick# => woof woof
ja yksityinen menetelmä:
> dog = Dog.new> dog.bark# => NoMethodError: private method `bark' called for <Dog>
Private class-menetelmät eivät välttämättä ole yhtä yleisiä kuin private instance-menetelmät, mutta niillä on silti paikkansa. Esimerkiksi luokkamenetelmä voi vaatia sisäisiä auttajamenetelmiä suorittaakseen tehtävänsä. Oli syy mikä tahansa, private class-menetelmien määrittelyllä on arvoa, mutta se ei ole aina intuitiivista.
tässä esimerkissä Dog
luokka on pidettävä yllä luetteloa tricks
, jota käytetään muissa julkisen luokan menetelmissä. Tämä luettelo ei saisi olla Dog
– luokan ulkopuolisten soittajien saatavilla.
väärä tie
ensisyöttö kirjoittaessa yksityinen tricks
menetelmä voi näyttää:
class Dog private def self.tricks endend
kuitenkin testattaessa tricks
– menetelmän näkyvyyttä:
> Dog.tricks# =>
Oho, ei virhe heitettiin osoittaa, että yksityinen menetelmä oli nimeltään, tämä menetelmä on täysin julkinen.
miksi?
syy siihen, ettei yllä oleva koodi tuottanut yksityistä menetelmää, liittyy Rubyn objektihierarkiaan, sisäisten luokkien väliseen vuorovaikutukseen, näiden luokkien esiintymiin ja eigenclasseihin. Yksityiskohtainen kirjoitus siitä, miten Rubyn esineet toimivat keskenään, löytyy aiemmasta viestistä.
luokittain määriteltäessä on erotettava oletuskonteksti ja self.
menetelmäilmoituksessa esitetty konteksti.
yksityisen menetelmän soveltamisalaa ei voida käyttää edellä mainitulla tavalla, koska se ei käsittele Dog
luokassa määriteltyjen ja self
kontekstissa määriteltyjen menetelmien välistä asiayhteyden muutosta.
joten mitkä ovat vaihtoehdot?
Luokka << self
yksi vaihtoehtoinen tapa määritellä luokkamenetelmiä objektille on käyttää class << self
syntaksia. Tämä syntaksi avaa eigenclass toimitetulle argumentille. Tässä esimerkissä self
Dog
luokan sisällä avaa Dog's
eigenclass.
class Dog class << self private def tricks end endend
on huomattava, että tämänkaltaisia menetelmiä määriteltäessä julistus on muuttunut def self.tricks
: stä yksinkertaisesti def tricks
: ksi.
nyt yksityinen laajuus säilyy ja odotettu käyttäytyminen saavutetaan:
> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
moduulit
moduulit Rubyssa ovat menetelmien ja vakioiden kokoelmia. Näitä kokoelmia voidaan käyttää kapselointivälineinä tai tässä tapauksessa vaihtoehtoina julkisen ja yksityisen luokan menetelmien määrittelylle.
kun Luokka extends
a moduuli, kaikki kyseisen moduulin menetelmät muuttuvat luokkamenetelmiksi aiheluokassa*. Tätä kaavaa voidaan käyttää tricks
– menetelmän määrittelyyn Dog
.
* Huom.: Tämä koskee vain ”tyypillisessä merkityksessä” määriteltyjä menetelmiä, jotka eivät ole def self.
tai def Dog.
moduulin metodimääritelmät eivät automaattisesti muutu luokan menetelmiksi samalla tavalla, kun extended
.
class Dog module ClassMethods private def tricks end end extend ClassMethodsend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
tämän lähestymistavan etuna on luettavuus. ClassMethods
– niminen moduuli, joka sisältyy ja siten kapseloi Dog
– luokan, on selkeä koti kaikille halutuille luokkamenetelmille.
näkyvyyden modifioijat kuten private
käyttäytyvät sen mukaisesti ja yksinkertainen extend
modulin määritelmän alareunassa tuo kaiken yhteen.
private_class_method
kolmas lähestymistapa on käyttää rakennettua menetelmää Module#private_class_method
. Menetelmän tarkoituksena on muuttaa olemassa olevien luokkamenetelmien näkyvyyttä.
toisin kuin kaksi muuta ratkaisua, tämä ei vaadi erityylistä menetelmän määrittelyä virheellisestä ratkaisusta:
class Dog def self.tricks end private_class_method :tricksend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
tämä menetelmä voidaan myös vuorata luokan ’ menetelmän määrittelyn aikana:
class Dog private_class_method def self.tricks endend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class
jos yhden luokan menetelmä on yksityinen ja säästö linjat on erittäin tärkeää, tämä tyyli voi olla sovellettavissa; mutta, se varmasti uhraa tason luettavuus.
private_class_method
suuri vahvuus on sen eksplisiittisyys. Toisin kuin muut lähestymistavat, tämä ei vaadi erityistä moduulin määrittelyä tai menetelmän määrittelyä konteksti kytkentä.
Jatkoluku
edellä mainitut ratkaisut hoitavat homman, mutta eivät välttämättä vastaa viipyileviin kysymyksiin siitä, miksi asiat toimivat niin kuin toimivat. Muutama suuri artikkeleita ruby eigenclass ja Matz ajatuksia Ruby method design pitäisi auttaa maalata tiiviimpi kuva, miksi Ruby ’ s private class method määritelmä on monimutkainen.