Menu
Coddy logo textTech

Soyut Metotlar

Coddy'nin Ruby Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 34 / 57.

Bir üst sınıf, bir algoritmanın adımlarını tanımlayabilir ve bazı adımları alt sınıflarına bırakabilir. Bu, şablon yöntemi kalıbıdır: aşağıdaki render sabittir; header ve row ise her rapora göre farklılık gösterir:

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]])

Çıktı:

name,price
pen,2
cup,5
(CsvReport)

Üst sınıf, bir alt sınıfın hangi metotları yazması gerektiğini yine belirtmelidir. Bunun için açık bir mesajla NotImplementedError yükselten bir soyut metot kullanılır:

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
end

Çıktı:

HtmlReport must implement row

NotImplementedError bir StandardError değildir, bu nedenle çıplak bir rescue onu yakalamaz. Bu, eksik bir yöntemin genel hata işleme tarafından yutulmasını önler; gerektiğinde onu adıyla yakalayın:

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)

Çıktı:

caught by name: missing step
false

Soyut metotların yanı sıra bir şablon, kanca metotları da sunabilir: alt sınıfların geçersiz kılabileceği varsayılan bir değere sahip adımlar. Yukarıdaki footer bir kancadır; include_total? gibi evet-hayır döndüren bir metot da öyledir:

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: varsayılan cevap
    false
  end
end
challenge icon

Görev

Kolay

Rapor sınıflarını tamamlayın. Report#render(items), başlık satırını, her öğe için bir row satırını ve footer satırını yeni satırlarla birleştirerek döndürür. header ve row(item) soyuttur: sınıf adı ve yöntemle birlikte NotImplementedError ve HtmlReport must implement row mesajını yükseltirler. footer, end of report döndüren bir kancadır. CsvReport, name,qty başlığına ve pen,3 satırlarına sahiptir. TextReport, NAME QTY başlığına, adı 8 karaktere doldurulmuş satırlara (pen 3) ve 2 items altbilgisine sahiptir. HtmlReport yalnızca [table] başlığını tanımlar.

Sağlanan kod, rapor türünü ilk satırdan ve öğeleri name qty satırları olarak okur, ardından render çıktısını veya hata mesajını yazdırır.

Kodunuz report.rb, csv_report.rb, text_report.rb ve html_report.rb dosyalarına gitmelidir. main.rb, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

require_relative 'report'
require_relative 'csv_report'
require_relative 'text_report'
require_relative 'html_report'

# Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
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
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online Ruby derleyicisi