Menu
CoddyTech

추상 메서드

Coddy Ruby 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 34번째.

슈퍼클래스는 알고리즘의 단계를 정의하고 일부 단계는 서브클래스가 구현하도록 남겨둘 수 있습니다. 이것이 템플릿 메서드 패턴입니다. 아래에서 render는 고정되어 있지만, header와 row는 보고서마다 다릅니다.

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

출력:

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

슈퍼클래스는 서브클래스가 어떤 메서드를 작성해야 하는지 계속 명시해야 합니다. 명확한 메시지와 함께 NotImplementedError를 발생시키는 추상 메서드를 사용하는 것이 관례입니다.

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

출력:

HtmlReport must implement row

NotImplementedError는 StandardError가 아니므로, 인수 없는 rescue는 이를 잡지 못합니다. 따라서 누락된 메서드가 일반적인 오류 처리 과정에서 무시되지 않습니다. 필요할 때는 이름을 지정해 rescue하세요:

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)

출력:

caught by name: missing step
false

추상 메서드와 함께 템플릿은 훅 메서드도 제공할 수 있습니다. 기본값이 있는 단계로, 하위 클래스에서 재정의할 수 있습니다. 위의 footer가 훅이며, 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?     # 훅: 기본 응답
    false
  end
end
challenge icon

챌린지

쉬움

보고서 클래스를 완성하세요. Report#render(items)는 헤더 행, 항목마다 하나씩의 row, 그리고 footer를 줄바꿈으로 연결하여 반환합니다. header와 row(item)은 추상 메서드입니다. 이 메서드들은 HtmlReport must implement row(클래스 이름과 메서드)을 포함해 NotImplementedError를 발생시킵니다. footer는 end of report을 반환하는 후크입니다. CsvReport의 헤더는 name,qty이고 행은 pen,3입니다. TextReport의 헤더는 NAME QTY이고, 이름을 8자로 채운 행(pen 3)과 푸터 2 items가 있습니다. HtmlReport는 헤더 [table]만 정의합니다.

제공된 코드는 첫 번째 줄에서 보고서 종류를 읽고, 항목을 name qty 형식의 줄로 읽은 다음 render 결과 또는 오류 메시지를 출력합니다.

코드는 report.rb, csv_report.rb, text_report.rb, html_report.rb에 작성하세요. main.rb에는 제공된 입력/출력 코드가 있으며 수정할 수 없습니다.

직접 해보기

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

# 제공된 입력/출력 코드: 그대로 유지하세요
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 icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Ruby 컴파일러