Abstrakte Methoden
Teil des Abschnitts Objektorientierte Programmierung der Ruby-Journey von Coddy. Lektion 34 von 57.
Eine Oberklasse kann die Schritte eines Algorithmus definieren und einige Schritte ihren Unterklassen überlassen. Dies ist das Template-Methoden-Muster: render unten ist festgelegt, während sich header und row je nach Bericht unterscheiden:
class Report
def render(items)
[header, *items.map { |i| row(i) }, footer].join("\n")
end
def footer
"(#{self.class.name})"
end
end
class CsvReport < Report
def header
"name,price"
end
def row(item)
item.join(",")
end
end
puts CsvReport.new.render([["pen", 2], ["cup", 5]])Ausgabe:
name,price
pen,2
cup,5
(CsvReport)Die Oberklasse sollte weiterhin angeben, welche Methoden eine Unterklasse implementieren muss. Üblicherweise handelt es sich dabei um eine abstrakte Methode, die NotImplementedError mit einer eindeutigen Nachricht auslöst:
class Report
def render(items)
[header, *items.map { |i| row(i) }].join("\n")
end
def header
raise NotImplementedError, "#{self.class} must implement header"
end
def row(_item)
raise NotImplementedError, "#{self.class} must implement row"
end
end
class HtmlReport < Report
def header
"[table]"
end
end
begin
puts HtmlReport.new.render([1])
rescue NotImplementedError => e
puts e.message
endAusgabe:
HtmlReport must implement rowNotImplementedError ist kein StandardError, daher fängt ein bloßes rescue ihn nicht ab. Dadurch wird verhindert, dass eine fehlende Methode von einer allgemeinen Fehlerbehandlung verschluckt wird; fange ihn beim Namen ab, wenn du Folgendes benötigst:
def risky
raise NotImplementedError, "missing step"
end
begin
begin
risky
rescue => e
puts "general handler: #{e.message}"
end
rescue NotImplementedError => e
puts "caught by name: #{e.message}"
end
puts NotImplementedError.ancestors.include?(StandardError)Ausgabe:
caught by name: missing step
falseNeben abstrakten Methoden kann eine Vorlage Hook-Methoden anbieten: Schritte mit einem Standardverhalten, die Unterklassen überschreiben können. footer oben ist ein Hook; ebenso eine Ja-oder-Nein-Methode wie include_total?:
class Report
def render(items)
lines = [header, *items.map { |i| row(i) }]
lines << total_line(items) if include_total?
lines.join("\n")
end
def include_total? # hook: Standardantwort
false
end
endAufgabe
EinfachVervollständige die Report-Klassen. Report#render(items) gibt die Kopfzeile, eine row-Zeile pro Element und den footer zurück, durch Zeilenumbrüche verbunden. header und row(item) sind abstrakt: Sie lösen NotImplementedError mit HtmlReport must implement row aus (dem Klassennamen und der Methode). footer ist ein Hook, der end of report zurückgibt. CsvReport hat die Kopfzeile name,qty und Zeilen wie pen,3. TextReport hat die Kopfzeile NAME QTY, Zeilen, in denen der Name auf 8 Zeichen aufgefüllt wird (pen 3), und den Footer 2 items. HtmlReport definiert nur die Kopfzeile [table].
Der bereitgestellte Code liest die Report-Art aus der ersten Zeile und die Elemente als Zeilen im Format name qty ein und gibt anschließend render oder die Fehlermeldung aus.
Dein Code gehört in report.rb, csv_report.rb, text_report.rb und html_report.rb. main.rb enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.
Probier es selbst
require_relative 'report'
require_relative 'csv_report'
require_relative 'text_report'
require_relative 'html_report'
# Gelieferter Ein-/Ausgabe-Code: belasse ihn wie er ist
input = []
while (line = gets)
input << line.chomp
end
kinds = { "csv" => CsvReport, "text" => TextReport, "html" => HtmlReport }
report = kinds[input[0]].new
items = input.drop(1).map(&:split)
begin
puts report.render(items)
rescue NotImplementedError => e
puts e.message
end
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Klassen und Objekte
Arbeiten mit DateienKlassen definierenInstanzvariablenMethoden und selfto_s und inspectRückblick – Bibliotheksausweis4Kapselung
Private MethodenGeschützte MethodenPrivate SetterZustand schützenRückblick – Verkaufsautomat7Polymorphismus und Duck Typing
PolymorphismusDuck TypingAbstrakte MethodenFälle und KlassenRückblick – Zahlungsmethoden2Getter und Setter sowie self
Leser und SchreiberBenutzerdefinierte Setterself in MethodenIdentität und GleichheitWiederholung – Kontaktliste5Vererbung
UnterklassenMethoden überschreibensuper aufrufenis_a? und VorfahrenRückblick – Gehaltsabrechnung des Personals8Spezielle Methoden
Gleichheit und HashOperator-MethodenIndexieren und AnhängenBenutzerdefinierte CollectionsRückblick – Brüche11Projekt: Bibliotheksverwaltung
Bücher und MitgliederBücher ausleihenÜbe selbstständig: Online-Ruby-Compiler