Ruby-Programmierung: Vererbung

Aus Wikibooks

Zurück zum Inhaltsverzeichnis.

Stellen Sie sich einen Baum vor. Er hat einen Stamm, Wurzeln und eine Krone. Betrachtet man nun jedoch zwei konkrete Bäume, z.B. Tanne und Birke, so zeigen sich Unterschiede in der Farbe des Stammes, der eine hat Blätter, der andere Nadeln und so weiter. Unser Verständnis von der Welt ist offensichtlich hierarchischer Art - zwar teilen alle Bäume die Eigenschaften von Bäumen, können sich aber in ihrer konkreten Ausprägung unterscheiden.

Diese hierarchische Form bei der Beschreibung der Welt findet man ebenfalls in objektorientierten Sprachen wieder. Durch Vererbung werden Eltern-Kind-Relationen zwischen den Klassen definiert, die es erlauben, das oben genannte Beispiel zu modellieren.

Vererbung[Bearbeiten]

Gehen wir in diesem Beispiel noch eine Stufe höher und erstellen eine Klasse Plant, von der wir konkrete Pflanzen, wie Bäume, ableiten wollen.

class Plant
  def initialize(name)
    @name = name
  end
end

Vererbung erfolgt mittels eines <. Dabei übernimmt die erbende Klasse alle Variablen und Methoden der Elternklasse.

class Tree < Plant
  def initialize(name)
    super(name)
    @has_trunk = true
  end
end

super ruft die gleichnamige Methode der Elternklasse auf und erlaubt es, dass sich eine Veränderung der Methoden der Elternklasse auch auf die Kinder vererbt, anstatt sie zu überschreiben.

Mehrfachvererbung/Mixins[Bearbeiten]

Mehrfachvererbung beschreibt die Möglichkeit, dass eine Klasse Eigenschaften von mehreren Elternklassen erbt. Ruby kennt keine direkte Mehrfachvererbung, sondern ermöglicht ein ähnliches Verhalten mit Mixins.

Mixins sind Module, die zu Klassen hinzugefügt werden und so diese Klassen um Funktionalität erweitern. Sie dienen meist dazu abstrakte Methoden bereitzustellen, die in mehreren Klassen sinnvoll angewendet werden können. Beispielsweise kann ein Baum wachsen, genauso wie ein Tier. Man könnte argumentieren, dass man ein gemeinsames Elternobjekt einfügen könnte (Lebewesen), das diese Methode bereitstellt, doch gibt es oft nicht diese einfache Möglichkeit neue Elternobjekte einzufügen.

module Growable
  def grow!
    @height ||= 0
    @velocity ||= 0.1
    @height += @velocity
    
    self
  end
end

class Tree
  attr_reader :height

  include Growable
end

puts Tree.new("Birch").grow!.grow!.height

In diesem Beispiel wird die Klasse Tree durch eine grow!-Methode erweitert. Dadurch ist es möglich, den selben Code auch in anderen Klassen zu verwenden, die gegebenenfalls unterschiedliche Elternklassen haben.

Hier zeigt sich auch der Unterschied zwischen den verschiedenen Möglichkeiten des letzten Kapitels Methoden auf Modulen zu definieren. Eine mit module_function definierte Modulmethode wird nicht der Objektinstanz hinzugefügt, kann aber innerhalb der Klasse ohne Modulprefix aufgerufen werden, im Gegensatz zu den anderen beiden aufgezeigten Varianten, die den Aufruf nur über den Modulnamen erlauben. Instanzmethoden werden wie oben gezeigt der Objektinstanz hinzugefügt.