Métodos Abstratos
Parte da seção Programação orientada a objetos do Journey de Ruby da Coddy. Lição 34 de 57.
Uma superclasse pode definir as etapas de um algoritmo e deixar algumas etapas para suas subclasses. Esse é o padrão de método template: render abaixo é fixo, enquanto header e row diferem para cada relatório:
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]])Saída:
name,price
pen,2
cup,5
(CsvReport)A superclasse ainda deve indicar quais métodos uma subclasse precisa escrever. A convenção é um método abstrato que gera NotImplementedError com uma mensagem clara:
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
endSaída:
HtmlReport must implement rowNotImplementedError não é um StandardError, portanto um rescue sem especificação não o captura. Isso impede que um método ausente seja ignorado pelo tratamento geral de erros; capture-o pelo nome quando precisar:
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)Saída:
caught by name: missing step
falseAlém dos métodos abstratos, um template pode oferecer métodos gancho: etapas com um comportamento padrão que as subclasses podem substituir. footer acima é um gancho; assim como um método de sim ou não, como 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: resposta padrão
false
end
endDesafio
FácilComplete as classes de relatório. Report#render(items) retorna a linha de cabeçalho, uma row por item e o footer, unidos por quebras de linha. header e row(item) são abstratos: eles geram NotImplementedError com HtmlReport must implement row (o nome da classe e o método). footer é um gancho que retorna end of report. CsvReport tem o cabeçalho name,qty e linhas pen,3. TextReport tem o cabeçalho NAME QTY, linhas com o nome preenchido até 8 caracteres (pen 3) e o rodapé 2 items. HtmlReport define apenas o cabeçalho [table].
O código fornecido lê o tipo de relatório da primeira linha e os itens como linhas name qty, depois imprime render ou a mensagem de erro.
Seu código deve ficar em report.rb, csv_report.rb, text_report.rb e html_report.rb. main.rb contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
require_relative 'report'
require_relative 'csv_report'
require_relative 'text_report'
require_relative 'html_report'
# Código de entrada/saída fornecido: mantenha-o como está
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
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação orientada a objetos
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesVariáveis de InstânciaMétodos e selfto_s e inspectRevisão - Cartão da Biblioteca4Encapsulamento
Métodos privadosMétodos protegidosSetters privadosProtegendo o estadoRevisão - Máquina de venda automática7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMétodos Abstratoscase e ClassesRevisão - Métodos de Pagamento2Acessores e self
Leitores e GravadoresSetters Personalizadosself nos MétodosIdentidade e IgualdadeRecapitulação - Lista de Contatos5Herança
SubclassesSobrescrita de métodosChamando superis_a? e ancestraisRevisão - Folha de pagamento da equipe8Métodos Especiais
Igualdade e hashMétodos de OperadoresIndexação e AdiçãoColeções PersonalizadasRevisão - Frações11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Compilador de Ruby online