Metodi astratti
Fa parte della sezione Programmazione orientata agli oggetti del percorso Ruby di Coddy. Lezione 34 di 57.
Una superclasse può definire i passaggi di un algoritmo e lasciarne alcuni alle sue sottoclassi. Questo è il pattern template method: render qui sotto è fisso, mentre header e row variano a seconda del report:
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]])Output:
name,price
pen,2
cup,5
(CsvReport)La superclasse dovrebbe comunque indicare quali metodi una sottoclasse deve implementare. La convenzione prevede un metodo astratto che genera NotImplementedError con un messaggio chiaro:
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
endOutput:
HtmlReport must implement rowNotImplementedError non è una StandardError, quindi un rescue senza argomenti non la intercetta. In questo modo, un metodo mancante non viene ignorato dalla gestione generale degli errori; intercettala per nome quando ne hai bisogno:
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)Output:
caught by name: missing step
falseAccanto ai metodi astratti, un modello può offrire metodi hook: passaggi con un comportamento predefinito che le sottoclassi possono sovrascrivere. footer qui sopra è un hook; lo è anche un metodo sì o no come 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? # punto de extensión: respuesta predeterminada
false
end
endSfida
FacileCompleta le classi dei report. Report#render(items) restituisce la riga di intestazione, una row per elemento e il footer, uniti da nuove righe. header e row(item) sono astratti: generano NotImplementedError con HtmlReport must implement row (il nome della classe e il metodo). footer è un hook che restituisce end of report. CsvReport ha l’intestazione name,qty e righe pen,3. TextReport ha l’intestazione NAME QTY, righe con il nome completato fino a 8 caratteri (pen 3) e il footer 2 items. HtmlReport definisce solo l’intestazione [table].
Il codice fornito legge il tipo di report dalla prima riga e gli elementi da righe name qty, quindi stampa render oppure il messaggio di errore.
Il tuo codice va inserito in report.rb, csv_report.rb, text_report.rb e html_report.rb. main.rb contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
require_relative 'report'
require_relative 'csv_report'
require_relative 'text_report'
require_relative 'html_report'
# Codice di input/output fornito: lascialo così com'è
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
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Classi e oggetti
Lavorare con i fileDefinire le classiVariabili d'istanzaMetodi e selfto_s e inspectRipasso - Tessera della biblioteca4Incapsulamento
Metodi privatiMetodi protettiSetter privatiProteggere lo statoRiepilogo - Distributore automatico7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMetodi astratticase e classiRiepilogo - Metodi di pagamento10Pattern di progettazione Parte 2
Delegazione con ForwardablePattern DecoratorPattern BuilderPattern State2Metodi di accesso e self
Metodi di lettura e scritturaSetter personalizzatiself nei metodiIdentità e uguaglianzaRiepilogo - Elenco contatti5Ereditarietà
SottoclassiRidefinizione dei metodiChiamare superis_a? e antenatiRiepilogo - Paghe del personale8Metodi speciali
Uguaglianza e hashMetodi degli operatoriIndicizzazione e appendCollezioni personalizzateRiepilogo - Frazioni11Progetto: Gestione della biblioteca
Libri e iscrittiPrendere in prestito i libriEsercitati da solo: Compilatore Ruby online