Ruby/Kontrola dostępu
Kontrola dostępu
edytujWcześniej powiedzieliśmy, że Ruby nie posiada funkcji, tylko metody. Jednakże jest nieco więcej różnych rodzajów metod. W tym rozdziale przedstawimy sposoby kontroli dostępu.
Rozważmy, co się stanie, gdy zdefiniujemy metodę na samym szczycie hierarchii, nie wewnątrz jakiejkolwiek klasy? Możemy myśleć o takiej metodzie analogicznie jak o funkcji w bardziej tradycyjnym języku, takim jak C.
def kwadrat(n)
n * n
end
kwadrat(5) #=> 25
Wydaje się, że nasza nowa metoda nie należy do żadnej klasy, ale w rzeczywistości Ruby dodał ją do klasy Object która jest nadklasą każdej innej klasy. W rezultacie każdy obiekt powinien mieć możliwość używania tej metody. Jest to prawdą, ale z małym kruczkiem: jest to prywatna metoda każdej klasy. Wprawdzie będziemy jeszcze dokładnie rozważać co to znaczy, ale zauważmy, że jedną z konsekwencji tego faktu jest to, że metoda ta może być wywołana tylko w funkcyjnym stylu, jak poniżej:
class Klasa
def czwarta_potega_z(x)
kwadrat(x) * kwadrat(x)
end
end
Klasa.new.czwarta_potega_z(10) #=> 10000
Wyraźnie nie możemy wywołać metody na rzecz obiektu:
"ryba".kwadrat(5)
ERR: (eval):1: private method `kwadrat' called for "ryba":String
To raczej zręcznie chroni czysto obiektową naturę Rubiego (funkcje są wciąż metodami obiektów, ale odbiorcą domyślnie jest self) dostarczając funkcji które mogą być zapisane podobnie jak w bardziej tradycyjnym języku.
Powszechną dyscypliną umysłową w programowaniu obiektowym, którą zasugerowaliśmy we wcześniejszym rozdziale, jest problem rozdzielenia specyfikacji i implementacji, czyli jakie zadania wymagamy by obiekt wypełniał i jak je właściwie wypełnia. Wewnętrzne prace obiektu powinny być zazwyczaj ukryte przed jego użytkownikami. Powinni oni dbać o to, co wchodzi i wychodzi do/z obiektu oraz ufać, że obiekt wie co robi wewnętrznie z danymi. Z tego powodu często pomocne jest, gdy klasa posiada metody niewidoczne z zewnątrz, ale używane wewnętrznie, które mogą być poprawione przez programistę kiedy tylko zajdzie taka potrzeba, bez zmieniania sposobu, w jaki użytkownicy widzą obiekty danej klasy. W trywialnym przykładzie poniżej, pomyśl o metodzie eval jako o niewidocznych pracach klasy.
class Test
def dwa_razy(a)
puts "#{a} razy dwa to #{wylicz(a)}"
end
def wylicz(b)
b*2
end
private :wylicz # to ukryje wylicz przed uzytkownikami
end
test = Test.new
test.wylicz(6)
ERR: (eval):1: private method `wylicz' called for #<Test:0x4017181c>
test.dwa_razy(6)
#=> 6 razy dwa to 12
Moglibyśmy oczekiwać, że test.wylicz(6) zwróci 12, ale zamiast tego nauczyliśmy się, że metoda wylicz jest niedostępna, gdy odgrywamy rolę użytkownika obiektu Test. Tylko inne metody klasy Test, takie jak dwa_razy mogą korzystać z wylicz. Od nas wymagane jest posługiwanie się publicznym interfejsem, który składa się z metody dwa_razy. Programista, który ma pod kontrolą tę klasę, może swobodnie modyfikować wylicz (tutaj, być może zmieniając b*2 na b+b i argumentując to przypuszczalnie wzrostem wydajności) bez wpływania na to jak użytkownik współdziała z obiektami klasy Test. Ten przykład jest oczywiście zbyt prosty by był użyteczny; korzyści z metod kontroli dostępu staną się bardziej widoczne tylko wtedy, gdy zaczniemy tworzyć bardziej skomplikowane i interesujące klasy.
Modyfikatory dostępu
edytujW Rubim mamy dostępne trzy modyfikatory dostępu.
Modyfikator | Tłumaczenie | Działanie |
---|---|---|
private | prywatny | Metoda dostępna tylko dla obiektu danej klasy. Każdy obiekt danej klasy może wywoływać metody prywatne tylko na rzecz samego siebie. W innych językach programowania (np. w Javie) obiekty tej samej klasy mogą wykonywać swoje metody prywatne. |
protected | chroniony | Metoda dostępna dla wszystkich obiektów danej klasy (lub klas potomnych). |
public | publiczny | Metoda dostępna dla wszystkich obiektów. |
W Rubim modyfikatory dostępu dotyczą tylko metod. Jeżeli nie stosujemy żadnych modyfikatorów dostępu, domyślnym modyfikatorem jest public, tak więc wszystkie metody (poza initialize) są domyślnie publiczne. Dostęp do metod można określać na dwa sposoby:
- Stosując słowa kluczowe przed definicjami metod
- Stosując symbole o nazwach metod
Modyfikatory przed definicjami metod
edytujclass Test
public # każda metoda (poza initialize, która jest prywatna) jest domyślnie publiczna
def pub_met1
end
def pub_met2
end
private # metody prywatne
def priv_met1
end
protected # metody chronione
def prot_met1
end
def prot_met2
end
end
Jak widzimy, modyfikatory dostępu (private, protected, public) występują tu przed definicjami metod.
Modyfikatory z symbolami
edytujIdentyczny efekt (z tym, że dostęp będzie nadawany dynamicznie) można uzyskać stosując modyfikatory oraz nazwy metod jako symbole. Co to są symbole powiemy dokładnie w rozdziale o symbolach.
class Test
def pub_met1
end
def pub_met2
end
def priv_met1
end
def prot_met1
end
def prot_met2
end
public :pub_met1, :pub_met2
private :priv_met1
protected :prot_met1, :prot_met2
end
Nazwy metod po modyfikatorach poprzedzone są dwukropkami (:) - tak właśnie oznaczamy symbole. Ale czym są owe symbole? Dowiedzmy się!