Menu
Coddy logo textTech

추상 메서드

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로는 이를 처리할 수 없습니다. 따라서 일반적인 오류 처리가 구현되지 않은 메서드를 삼켜 버리는 것을 방지할 수 있습니다. 필요할 때는 이름을 지정하여 처리하세요:

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 컴파일러