Ruby dostarcza konstruktora o nazwie Module
, który jest czymś w rodzaju cienkiej klasy. Na początku Programiści Ruby mogą patrzeć na moduły jak na” szufladę śmieci ” kodu, która jest po prostu wyrzucana i używana do porządkowania plików, ale jest pewna metoda tego szaleństwa. Klasa Ruby Class
dziedziczy z Module
I dodaje takie rzeczy jak instancje, właściwości itp. – wszystko, co normalnie można by pomyśleć, że Klasa miałaby. Ponieważ Module
jest dosłownie przodkiem Class
, oznacza to, że moduły mogą być w pewien sposób traktowane jak Klasy.
najważniejsze, aby zrozumieć, jak działa Łańcuch przodków Ruby. Jak wszystkie języki OOP, Ruby wspiera dziedziczenie. Kiedy dziedziczysz po klasie, Klasa nadrzędna jest dodawana do łańcucha przodków. Możesz wyświetlić przodków dowolnej klasy, wywołującancestors
na niej:
class Foo < BarendFoo.ancestors#=>
jak wspomniano, możesz znaleźćModule
w tablicyClass.ancestors
.
gdyinclude
moduł do twojej klasy, moduł jest dodawany do łańcucha przodków twojej klasy – tak jak Klasa. To sprawia, że include
jest tylko formą dziedziczenia, nie ma w tym nic specjalnego.
module Barendclass Foo include BarendFoo.ancestors#=>
wszystkie metody wBar
są dodawane doFoo
jako metody instancji. Ponieważ Bar znajduje się w łańcuchu, możesz nawet wywołać super
z niego, aby wywołać metody nad nim w łańcuchu, niezależnie od tego, czy są zdefiniowane w modułach czy klasach.
class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world
mimo żeBar
jest modułem,super
nadal wywołuje łańcuch i takBaz#hello
jest również wywoływany. Warto zauważyć, że Bar
jest dodawany do łańcucha przodków przed Baz. Gdy moduł jest dołączony, jest zawsze dodawany bezpośrednio na jego klasie. Może to być mylące podczas dodawania wielu modułów, ponieważ są one zawarte w kolejności „odwrotnej” :
class Foo include A include BendFoo.ancestors#=>
gdyA
jest dołączony, jest wstawiany bezpośrednio nadFoo
. Ale gdy B
jest dołączony, jest również wstawiany bezpośrednio nad Foo
, więc ląduje przed A
.
include vs extend
include
jest wystarczająco łatwe do zrozumienia, dodaje metody modułu jako metody instancji do jego klasy. Możesz pomyśleć o tym, że extend
robi to samo, ale zamiast tego dodaje metody jako metody klasy.
module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'
prepend
oprócz include/extend, Ruby 2.0+ dodaje metodę prepend
prepend
jest podobny do include
, ale zamiast tego wstawia moduł przed klasą include w łańcuchu dziedziczenia.
class Foo include Bar prepend BazendFoo.ancestors#=>
w Rubim możesz ponownie otworzyć dowolną klasę i przedefiniować metody na niej-nie wydaje się przydatne nadpisywanie metod na klasie za pomocą preparowanego modułu, w przeciwieństwie do przedefiniowania ich. prepend
przydaje się wtedy, gdy nadal potrzebujesz oryginalnej implementacji metody, ponieważ preparowane moduły mogą nadpisywać metody, ale nadal używają super
, aby wywołać oryginalną implementację.