Rozmowy rekrutacyjne, a zwłaszcza ich część techniczna najczęściej przebiegają według jakiegoś określonego schematu. Łatwo przewidzieć pytania, jakie mogą paść. Często jest tak, że developer, który je zadaje jest wyrwany z projektu i na co dzień zajęty rozwiązywaniem problemów i nie ma czasu przygotować jakichś super oryginalnych pytań (chyba że jest sadystą i lubi znęcać się na kandydatach, ale kto z nas nie prowadził rekrutacji i nie miał w zanadrzu pytania killera?), więc googluje np. „Ruby interview questions”. Druga możliwość jest taka, że ten developer przeprowadza już n-tą rozmowę, z czystej rutyny zadaje zawsze te same pytania. Może też pytać o to, o co sam został zapytany, gdy to on był kandydatem. Chcę Ci przedstawić i wytłumaczyć kwestię, która na 90% pojawi się na rozmowie rekrutacyjnej dla programisty Ruby on Rails, a chodzi o to czym jest modyfikator Protected w Ruby.
Jaka jest różnica między Public, Private i Protected, czyli modyfikatorami dostępu?
Brzmi znajomo?
Możliwe, że spotykasz się z tymi słowami w innych językach. Aby zrozumieć ich nieco odmienne znaczenie w Ruby przyjrzyjmy się dla porównania jak funkcjonują w Javie, C# i PHP.
Java
Public – dostęp do metody w danym pakiecie jak i w każdym innym
Private – dostęp tylko w obrębie klas i niemożliwe do dziedziczenia
Protected – jest prawie identyczny jak private, z jedną subtelną różnicą, metody protected mogą być dziedziczone
C#
Public – dostęp do metody jest nieograniczony z każdego miejsca w aplikacji
Private – metody dostępne tylko w obrębie klasy lub struktury, w której są zdefiniowane
Protected – metoda jest dostępna w potomnej klasie tylko, jeśli dostęp odbywa się poprzez klasę potomną
PHP
Public – metoda jest widoczna ze środka klasy, klas pochodnych oraz na zewnątrz klasy
Private – metody dostępne tylko i wyłącznie ze środka klasy
Protected – metoda jest widoczna we wszystkich klasach, które dziedziczą po klasie bazowej, włączając w to także klasę bazową
RUBY 💖💋💪
W pierwszej kolejności, gwoli wyjaśnienia, te trzy słowa: public, private, protected, określane potocznie jako modyfikatory dostępu, tak naprawdę nie są słowami kluczowymi, ale… metodami.
Pamiętaj, że w języku Ruby robiący coś i możliwy do wywołania kod określa się właśnie słowem metoda, a definiuje się przez słowa def i end na pozątku i na końcu danej partii kodu.
Public w Ruby
Niczym się nie różni od innych języków. W Ruby wszystkie metody nieokreślone wyraźnie dwoma pozostałymi modyfikatorami są publiczne, z wyjątkiem konstruktora klasy, czyli metody initialize, która zawsze jest prywatna.
Metody publiczne mogą być wywołane przez każdego i wszędzie, nie podlegają tym samym żadnym ograniczeniom. Aby metoda była publiczna nie jest wymagane żadne słowo kluczowe, wystarczy, że będzie zadeklarowana powyżej deklaracji private i protected.
Ciekawostka!
Metody publiczne zadeklarowane globalnie poza wszystkimi klasami są tak naprawdę metodami prywatnymi egzemplarza klasy Object, czyli Ruby’owej super ekstra klasy matki.
Private w Ruby
Odbiorcą metody prywatnej zawsze jest self.
Nie można ich wywołać dla żadnej instancji klasy, w której są zdefiniowane, ponieważ działają tylko wewnątrz, w obrębie tej klasy, a to oznacza, że mogą być wywołane jedynie w kontekście danego obiektu.
Można je wywołać tylko w innych metodach egzemplarza tej samej klasy i jej podklas. Metody prywatne w Ruby są dziedziczone.
Przy korzystaniu z metod prywatnych w ciele innych metod należy pamiętać, że zawsze robimy to w stylu funkcyjnym czyli:
metoda_prywatna()
a nie
instancja.metoda_prywatna()
lub
self.metoda_prywatna()
Z tego wynika też, że nie ma dostępu do prywatnych metod innego obiektu nawet, jeśli ten obiekt jest tej samej klasy.
Protected w Ruby
Dostęp do metod protected jest ograniczony tylko do rodziny, ale w porównaniu z innymi językami, mogą być wywoływane przez obiekty tej samej klasy, ale wewnątrz tych obiektów.
Można je wywołać zawsze na rzecz dowolnego egzemplarza klasy lub jej podklas, a więc w przeciwieństwie do private, nie ogranicza się ich tylko do niejawnych wywołań na rzecz self.
Protected stosuje się, aby operować na stanie wewnętrznym innych obiektów tej samej klasy.
Jest to metoda dostępowa pozwalająca egzemplarzowi danej klasy na współdzielenie stanu wewnętrznego, ale jednocześnie zabrania konsumentom tej klasy uzyskać dostęp do tego stanu z zewnątrz.
Cytując Matza, twórcę Ruby’ego:
“Metoda chroniona zdefiniowana w klasie C może zostać wywołana na rzecz obiektu O przez metodę w obiekcie P, jeśli klasy O i P są podklasami klasy C lub są jej równe.”
Pora na przykłady, żeby lepiej to zrozumieć modyfikator Protected w Ruby.
Mamy klasę Employee i dwóch pracowników symbolizujących jej instancje. Załóżmy scenariusz, że szef chce porównać ich pensje, jednocześnie nie ujawniając ich na zewnątrz.
class Employee
attr_reader :salary
protected :salary
def greater_salary_than(other_employee)
@salary > other_employee.salary
end
end
first_employee = Employee.new
second_employee = Employee.new
first_employee.grater_salary_than(second_employee)
class Persondef older_than?(other_person)
age > other_person.age
end
protected
def age@age
end
end
Dobrze widać tutaj to, o czym pisałem powyżej. Metoda chroniona nie jest dostępna poza kontekstem danego obiektu, ale jest dostępna wewnątrz kontekstu innego obiektu, wtedy i tylko wtedy gdy obiekt ten jest tego samego typu.
Dodatkowe informacje o Protected w Ruby i pozostałych modyfikatorach
- metoda chroniona może być wywołana w kontekście danego obiektu jako
metoda()
alboself.metoda()
- modyfikatory dostępu można deklarować na dwa sposoby:
- wszystkie metody po słowie private będą metodami prywatnymi, chyba, że gdzieś po drodze użyjemy protected. I tutaj analogicznie, wszystkie metody po tej deklaracji będą chronione, chyba, że gdzieś po drodze zastosujemy modyfikator private
- drugi sposób, to najpierw zadeklarowanie wszystkich metod, a potem ustanowienie ich dostępu poprzez wylistowanie ich nazw w połączeniu z odpowiednim modyfikatorem dostępu
# I sposób
private
def metoda
protected
def metoda# II sposób
def metodaend
protected :metoda
- wywołanie metody
respond_to?
dla metody chronionej zwrócifalse
. Dla wyjaśnienia,respond_to?
to metoda, która zwracatrue
, jeśli obiekt implementuje metodę podaną jako argument. Domyślnie nie uwzględnia metod prywatnych. Można je brać pod uwagę przekazując do tej metody drugi argument jakotrue
- wróćmy jeszcze na chwilę do prywatnych metod. Wprawdzie pisałem, że nie mamy do nich dostępu, ale jest tu jeden wyjątek. Trik znany tylko tym, którzy nie mówią Rabi. Mianowicie, można się do nich dostać wywołując metodę prywatną za pomocą metody
send
albo ewaluując blok w kontekście obiektu posługując się metodąinstance_eval
p = Page.new
p.send :some_private_method
p.instance_eval(some_private_method)
To jest temat na inny wywód, potraktuj to jako szwajcarską ciekawostkę nie próbuj tego w domu.
BTW, jest jeszcze taka metoda public_send
, która działa jak send
, przy czym pomija metody prywatne. Łatwo pomylić.
Skoro wiesz jak stosować modyfikator protected w Ruby, zobacz też, o co chodzi z symbolami w Ruby.