Menu
Coddy logo textTech

Polymorphismus

Teil des Abschnitts Objektorientierte Programmierung der Ruby-Journey von Coddy. Lektion 32 von 57.

Polymorphismus bedeutet, dass ein Methodenaufruf mit Objekten verschiedener Klassen funktioniert und jedes Objekt auf seine eigene Weise antwortet. Code, der eine Schleife über Formen ausführt, ruft für jede area auf, ohne zu fragen, um welche Art von Form es sich handelt:

class Shape
  def to_s
    format("%s %.2f", self.class.name.downcase, area)
  end
end

class Circle < Shape
  def initialize(r)
    @r = r
  end

  def area
    3.14159 * @r * @r
  end
end

class Square < Shape
  def initialize(side)
    @side = side
  end

  def area
    @side * @side
  end
end

shapes = [Circle.new(1), Square.new(3)]
shapes.each { |s| puts s }
puts format("total %.2f", shapes.sum(&:area))

Ausgabe:

circle 3.14
square 9.00
total 12.14

Ohne Polymorphie muss der Aufrufer die Art jedes Objekts prüfen und diese Prüfung überall dort wiederholen, wo der Unterschied relevant ist. Mit Polymorphie liegt der Unterschied innerhalb jeder Klasse:

# ohne Polymorphismus
case shape.kind
when "circle" then 3.14159 * shape.r ** 2
when "square" then shape.side ** 2
end

# mit Polymorphismus
shape.area

Das Hinzufügen einer neuen Art von Objekt erfordert dann keine Änderung am aufrufenden Code: Eine neue Unterklasse mit ihrer eigenen area-Methode funktioniert in jeder bereits vorhandenen Schleife:

class Shape
  def describe
    "area #{area}"
  end
end

class Square < Shape
  def area
    4
  end
end

class Triangle < Shape
  def area
    6
  end
end

[Square.new, Triangle.new].each { |s| puts s.describe }

Ausgabe:

area 4
area 6

to_s ist das alltägliche Beispiel: puts ruft es für jedes Objekt auf, und jede Klasse antwortet anders. Deine Klassen machen mit, indem sie ihr eigenes to_s definieren:

class Coin
  def to_s
    "a coin"
  end
end

[42, "text", nil, [1, 2], Coin.new].each { |x| puts "[#{x}]" }

Ausgabe:

[42]
[text]
[]
[[1, 2]]
[a coin]
challenge icon

Aufgabe

Einfach

Vervollständige die Formen. Shape#to_s gibt circle: 3.14 zurück, den Klassennamen in Kleinbuchstaben und die Fläche mit zwei Dezimalstellen, und jede Unterklasse stellt area bereit: Circle.new(r) (verwende 3.14159 für Pi), Rectangle.new(w, h) und Triangle.new(base, height).

Der bereitgestellte Code liest Zeilen wie circle 1, rectangle 2 3 oder triangle 4 5, gibt jede Form aus, danach total: 22.14 und largest: rectangle: 6.00, und arbeitet ausschließlich mit to_s und area.

Dein Code gehört in shape.rb, circle.rb, rectangle.rb und triangle.rb. main.rb enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

require_relative 'shape'
require_relative 'circle'
require_relative 'rectangle'
require_relative 'triangle'

# Gelieferter Ein-/Ausgabe-Code: belasse ihn wie er ist
input = []
while (line = gets)
  input << line.chomp
end
kinds = { "circle" => Circle, "rectangle" => Rectangle, "triangle" => Triangle }
shapes = input.map do |line|
  kind, *numbers = line.split
  kinds[kind].new(*numbers.map(&:to_f))
end
shapes.each { |s| puts s }
puts format("total: %.2f", shapes.sum(&:area))
puts "largest: #{shapes.max_by(&:area)}"
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Ruby-Compiler