in-Depth Ruby: Modules & Include vs. Extend

Ruby poskytuje konstrukt nazvaný Module což je něco jako tenká Třída. Zpočátku se Ruby devs může dívat na moduly jako na „nevyžádanou zásuvku“ kódu, který je právě hozen a používán k uspořádání souborů, ale k tomuto šílenství existuje metoda. Ruby třídy Class dědí z Module a přidává věci jako instance, vlastnosti, atd – všechny ty věci, které by normálně si myslím, že třída bude mít. Protože Module je doslova předkem Class, znamená to, že moduly mohou být v některých ohledech považovány za třídy.

nejdůležitější je pochopit, jak funguje řetězec Ruby ancestor. Stejně jako všechny jazyky OOP, Ruby podporuje dědičnost. Když zdědíte z třídy, supertřída se přidá do řetězce předků. Můžete zobrazit předků nějaké třídy voláním ancestors na to:

class Foo < BarendFoo.ancestors#=> 

Jak již bylo zmíněno, můžete najít Module v poli Class.ancestors.

když include modul do vaší třídy, modul je přidán do řetězce předků vaší třídy-stejně jako třída. To dělá include jen formou dědičnosti, na tom není nic zvláštního.

module Barendclass Foo include BarendFoo.ancestors#=> 

Všechny metody v Bar jsou přidány do Foo jako metody instance. Protože Bar je v řetězci, můžete dokonce volat super z něj volat metody nad ním v řetězci, ať už jsou definovány na modulech nebo třídách.

class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world

I když Bar je modul, super stále volá do řetězce a tak Baz#hello je také nazýván. Stojí za zmínku, že Bar je přidán do řetězce předků před Baz. Je-li součástí modulu, je vždy přidán přímo na vrcholu je včetně třídy. To může být matoucí při přidávání více modulů, protože jsou zahrnuty v „obráceném“ pořadí:

class Foo include A include BendFoo.ancestors#=> 

Pokud je zahrnut A, je vložen přímo nad Foo. Ale když je zahrnuta B, je také vložena přímo nad Foo, takže skončí přistání před A.

include vs extend

include je dostatečně snadné pochopit, přidává metody modulu jako metody instance do třídy včetně. Můžete si myslet, že extend dělá totéž, ale místo toho přidává metody jako metody třídy.

module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'

prepend

kromě include/extend, Ruby 2.0 + přidá metodu prependprepend je podobný include, ale místo toho vloží modul před třídu including v řetězci dědičnosti.

class Foo include Bar prepend BazendFoo.ancestors#=> 

V Ruby můžete re-otevřít všechny třídy a předefinovat metody na to – to nebude zdát užitečné pro přepsání metody třídy pomocí předřazen modul jako protiklad k předefinování. Kde prepend přijde vhod, je, když budete ještě potřebovat původní implementace metody, protože předřazen moduly mohou přepsat metody, ale stále používat super volat původní implementaci.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.