Ruby/Kontrola dostępu: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Szymon wro (dyskusja | edycje)
Szymon wro (dyskusja | edycje)
Nie podano opisu zmian
Linia 5:
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.
 
<source lang="ruby">
<pre>
ruby> def kwadrat(n)
| n * n
| end
 
nil
ruby> kwadrat(5) #=> 25
</source>
25
</pre>
 
Wydaje się, że nasza nowa metoda nie należy do żadnej klasy, ale w rzeczywistości Ruby dodał ją do klasy <tt>Object</tt> 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:
 
<source lang="ruby">
<pre>
ruby> class FooKlasa
| def czwarta_potega_z(x)
| kwadrat(x) * kwadrat(x)
| end
| end
 
nil
ruby> Foo.new.czwarta_potega_z (10) #=> 10000
</source>
10000
</pre>
 
Wyraźnie nie możemy wywołać metody na rzecz obiektu:
 
<source lang="ruby">
<pre>
ruby> "ryba".kwadrat(5)
ERR: (eval):1: private method `kwadrat' called for "ryba":String
</presource>
 
To raczej zręcznie chroni czysto obiektową naturę Rubiego (funkcje są wciąż metodami obiektów, ale odbiorcą domyślnie jest <tt>self</tt>) dostarczając funkcji które mogą być zapisane podobnie jak w bardziej tradycyjnym języku.
Linia 38 ⟶ 36:
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 <tt>wylicz</tt> jako o niewidocznych pracach klasy.
 
<source lang="ruby">
<pre>
ruby> class Test
| def dwa_razy(a)
| puts "#{a} razy dwa to #{wylicz(a)}"
| end
| def wylicz(b)
def | wylicz(b*2)
| b*2
end
| private :wylicz # to ukryje wylicz przed uzytkownikami
| end
end
Test
 
ruby> test = Test.new
test = #<Test:0x4017181c>.new
<source>
ruby> test.wylicz(6)
 
<source lang="ruby">
ruby> test.wylicz(6)
ERR: (eval):1: private method `wylicz' called for #<Test:0x4017181c>
</source>
ruby> test.dwa_razy(6)
 
6 razy dwa to 12
<source lang="ruby">
nil
ruby> test.dwa_razy(6)
</pre>
#=> 6 razy dwa to 12
</source>
 
Moglibyśmy oczekiwać, że <tt>test.wylicz(6)</tt> zwróci <tt>12</tt>, ale zamiast tego nauczyliśmy się, że metoda <tt>wylicz</tt> jest niedostępnyniedostępna, gdy odgrywamy rolę użytkownika obiektu <tt>Test</tt>. Tylko inne metody klasy <tt>Test</tt>, takie jak <tt>dwa_razy</tt> mogą korzystać z <tt>wylicz</tt>. Od nas wymagane jest posługiwanie się publicznym interfejsem, który składa się z metody <tt>dwa_razy</tt>. Programista, który jest pod kontrolą tej klasy może swobodnie modyfikować <tt>wylicz</tt> (tutaj, być może zmieniając <tt>b*2</tt> na <tt>b+b</tt> i argumentując to przypuszczalnie wzrostem wydajności) bez wpływania na to jak użytkownik współdziała z obiektami klasy <tt>Test</tt>. 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 ==
 
W Rubim mamy dostępne trzy modyfikatory dostępu.
 
{| class="wikitable"
! Modyfikator
! Działanie
|-
| <tt>private</tt>
| 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) można wykonywać obiekty tej samej klasy mogą wykonywać swoje metody prywatne.
|-
| <tt>protected</tt>
| Metoda dostępna dla wszystkich obiektów danej klasy i klas potomnych.
|-
| <tt>public</tt>
| Metoda dostępna dla wszystkich obiektów.
|}
 
 
Moglibyśmy oczekiwać, że <tt>test.wylicz(6)</tt> zwróci <tt>12</tt>, ale zamiast tego nauczyliśmy się, że <tt>wylicz</tt> jest niedostępny, gdy odgrywamy rolę użytkownika obiektu <tt>Test</tt>. Tylko inne metody klasy <tt>Test</tt>, takie jak <tt>dwa_razy</tt> mogą korzystać z <tt>wylicz</tt>. Od nas wymagane jest posługiwanie się publicznym interfejsem, który składa się z metody <tt>dwa_razy</tt>. Programista, który jest pod kontrolą tej klasy może swobodnie modyfikować <tt>wylicz</tt> (tutaj, być może zmieniając <tt>b*2</tt> na <tt>b+b</tt> i argumentując to przypuszczalnie wzrostem wydajności) bez wpływania na to jak użytkownik współdziała z obiektami klasy <tt>Test</tt>. 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.
 
Dodatkowo warto zwrócić uwagę na oznaczanie nazw metod jako ''symboli'' (nazwa poprzedzona dwukropkiem) po modyfikatorze <tt>private</tt>. Gdybyśmy chcieli ukryć obie metody klasy <tt>Test2</tt> kod wyglądałby następująco: