In-Depth Ruby: Modules & Include vs. Extend

Ruby bietet ein Konstrukt namens Module , das einer dünnen Klasse ähnelt. Zunächst könnten Ruby-Entwickler Module wie eine „Junk-Schublade“ aus Code betrachten, die einfach herumgeworfen und zum Organisieren von Dateien verwendet wird, aber es gibt eine Methode für diesen Wahnsinn. Die Ruby-Klasse Class erbt von Module und fügt Dinge wie Instanziierung, Eigenschaften usw. hinzu – alles Dinge, die Sie normalerweise für eine Klasse halten würden. Da Module buchstäblich ein Vorfahr von Class , bedeutet dies, dass Module in gewisser Weise wie Klassen behandelt werden können.

Am wichtigsten zu verstehen ist, wie die Ruby-Ahnenkette funktioniert. Wie alle OOP-Sprachen unterstützt Ruby Vererbung. Wenn Sie von einer Klasse erben, wird die Oberklasse zu Ihrer Ahnenkette hinzugefügt. Sie können die Vorfahren jeder Klasse anzeigen, indem Sie ancestors aufrufen:

class Foo < BarendFoo.ancestors#=> 

Wie bereits erwähnt, finden Sie Module im Array Class.ancestors.

Wenn Sie include ein Modul in Ihre Klasse einfügen, wird das Modul zur Ahnenkette Ihrer Klasse hinzugefügt – genau wie eine Klasse. Dies macht include nur zu einer Form der Vererbung, daran ist nichts Besonderes.

module Barendclass Foo include BarendFoo.ancestors#=> 

Alle Methoden in Bar werden als Instanzmethoden zu Foo hinzugefügt. Da sich Bar in der Kette befindet, können Sie sogar super aufrufen, um Methoden darüber in der Kette aufzurufen, unabhängig davon, ob sie für Module oder Klassen definiert sind.

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

Obwohl Bar ein Modul ist, super ruft immer noch die Kette auf und so wird auch Baz#hello aufgerufen. Es ist erwähnenswert, dass Bar der Ahnenkette vor Baz hinzugefügt wird. Wenn ein Modul enthalten ist, wird es immer direkt über der Including-Klasse hinzugefügt. Dies kann beim Hinzufügen mehrerer Module verwirrend werden, da sie in „umgekehrter“ Reihenfolge enthalten sind:

class Foo include A include BendFoo.ancestors#=> 

Wenn A enthalten ist, wird es direkt über Foo eingefügt. Wenn jedoch B enthalten ist, wird es auch direkt über Foo eingefügt, sodass es vor A landet.

include vs extend

include ist leicht genug zu verstehen, es fügt die Methoden des Moduls als Instanzmethoden zu seiner Including-Klasse hinzu. Sie können sich extend vorstellen, dasselbe zu tun, aber stattdessen die Methoden als Klassenmethoden hinzuzufügen.

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

prepend

Zusätzlich zu include/extend fügt Ruby 2.0+ die prepend Methode hinzu. prepend ähnelt include , fügt jedoch das Modul vor der Including-Klasse in die Vererbungskette ein.

class Foo include Bar prepend BazendFoo.ancestors#=> 

In Ruby können Sie jede Klasse erneut öffnen und die Methoden neu definieren – es scheint nicht sinnvoll zu sein, Methoden für eine Klasse mit einem vorangestellten Modul zu überschreiben, anstatt sie neu zu definieren. Wo prepend nützlich ist, ist, wenn Sie noch die ursprüngliche Implementierung der Methode benötigen, da vorangestellte Module Methoden überschreiben können, aber immer noch super um die ursprüngliche Implementierung aufzurufen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.