Metody prywatnej klasy Ruby

24 Jan 2016

w języku programowania Ruby zdefiniowane metody występują w dwóch wariantach: instance methods i class methods. Metody instancji są dostępne po zainicjowaniu obiektu, tworząc instancję. Z drugiej strony metody klasowe są dostępne bez tworzenia instancji klasy, na której są zdefiniowane.

metody Rubiego mogą się różnić w widoczności. Metody publiczne są dostępne w dowolnym kontekście, podczas gdy dostępność metod prywatnych jest ograniczona w instancji klasy i jej potomków. Trzeci zakres widoczności, protected, zachowuje się podobnie do metod prywatnych, ale metody chronione mogą być wywoływane przez inne instancje tej samej klasy.

dla szybkiego odświeżania, publiczne i prywatne metody instancji wyglądają tak:

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

gdy wywołana jest metoda publiczna:

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

i metoda prywatna:

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

prywatne metody klasowe mogą nie być tak powszechne jak prywatne metody instancji, ale nadal mają swoje miejsce. Na przykład, metoda klasy może wymagać wewnętrznych metod pomocniczych do wykonania swojej funkcji. Niezależnie od przyczyny, definiowanie metod klasy prywatnej ma wartość, ale nie zawsze jest intuicyjne.

ten przykład Dog klasy musi utrzymywać listę tricks, która będzie używana w innych metodach klasy publicznej. Ta lista nie powinna być dostępna dla osób spoza klasy Dog.

the wrong way

pierwsze przejście przy pisaniu prywatnej metody tricks może wyglądać tak:

class Dog private def self.tricks endend

jednak podczas badania widoczności metody tricks :

> Dog.tricks# => 

Uh oh, nie został wyrzucony błąd wskazujący na to, że została wywołana prywatna metoda, ta metoda jest całkowicie publiczna.

dlaczego?

powód, dla którego powyższy kod nie stworzył prywatnej metody, ma związek z hierarchią obiektów Rubiego, interakcjami między wewnętrznymi klasami, instancjami tych klas i własnymi enklasami. Szczegółowy opis tego, jak obiekty Ruby współpracują ze sobą, można znaleźć w poprzednim poście.

podczas definiowania metod w klasie, kontekst domyślny i kontekst wprowadzony przez deklarację metody self. są różne.

zakres metody prywatnej nie może być użyty w powyższy sposób, ponieważ nie obsługuje zmiany kontekstu między metodami zdefiniowanymi w klasie Dog i zdefiniowanymi w kontekście self.

więc jakie są alternatywy?

class << self

alternatywnym sposobem definiowania metod klasy na obiekcie jest użycie składni class << self. Ta składnia otwiera enklass własny dla dostarczonego argumentu. W tym przykładzie self wewnątrz klasy Dog otworzy enklasę własną Dog's.

class Dog class << self private def tricks end endend

należy zauważyć, że podczas definiowania metod takich jak ta, deklaracja zmieniła się z def self.tricks NA po prostu def tricks.

teraz prywatny zakres jest zachowany i osiągnięto oczekiwane zachowanie:

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

Moduły

Moduły w Rubim są zbiorami metod i stałych. Zbiory te mogą być używane jako narzędzia do enkapsulacji lub, w tym przypadku, alternatywy dla definiowania metod klasy publicznej i prywatnej.

gdy Klasa extends jest modułem, wszystkie metody w tym module stają się metodami klasowymi w klasie przedmiotu*. Wzorzec ten można wykorzystać do zdefiniowania metody tricks na Dog.

* Uwaga: Dotyczy to tylko metod zdefiniowanych w „typowym znaczeniu” dowolne def self. lub def Dog. definicje metod w module nie stają się automatycznie metodami klasowymi w ten sam sposób, gdy extended.

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

zaletą takiego podejścia jest czytelność. Moduł o nazwie ClassMethods, który jest zawarty i tym samym zamknięty przez klasę Dog, jest czystym domem dla wszystkich pożądanych metod klasowych.

modyfikatory widoczności, takie jak private, zachowują się odpowiednio, a prosta extend na dole definicji modułu łączy to wszystko razem.

private_class_method

trzecim podejściem jest użycie wbudowanej metody Module#private_class_method. Celem tej metody jest zmiana widoczności istniejących metod klasowych.

w przeciwieństwie do dwóch pozostałych rozwiązań, ten nie wymaga innego stylu definicji metody od błędnego rozwiązania:

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

metoda ta może być również wbudowana podczas definiowania metody klasy:

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

jeśli pojedyncza metoda klasy musi być prywatna, a zapisywanie linii jest bardzo ważne, ten styl może mieć zastosowanie; ale z pewnością poświęca poziom czytelności.

główną siłą private_class_method jest jego wyraźność. W przeciwieństwie do innych podejść, ta nie wymaga specjalnej definicji modułu ani przełączania kontekstu definicji metody.

Czytaj dalej

powyższe rozwiązania wykonają zadanie, ale mogą nie odpowiadać na pytania o to, dlaczego wszystko działa tak, jak działa. Kilka świetnych artykułów na temat Ruby eigenclass i przemyślenia Matza na temat projektowania metody Ruby powinny pomóc w bardziej zwięzłym obrazie tego, dlaczego definicja metody prywatnej klasy Ruby jest złożona.

You might also like

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.