Phương thức trừu tượng
Thuộc phần Lập trình hướng đối tượng trong hành trình Ruby của Coddy. Bài học 34 trên 57.
Lớp cha có thể định nghĩa các bước của một thuật toán và để lại một số bước cho các lớp con. Đây là mẫu template method: render bên dưới được cố định, còn header và row khác nhau tùy theo báo cáo:
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]])Đầu ra:
name,price
pen,2
cup,5
(CsvReport)Lớp cha vẫn nên chỉ rõ những phương thức nào lớp con phải viết. Quy ước là dùng một phương thức trừu tượng và phát sinh NotImplementedError kèm thông báo rõ ràng:
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Đầu ra:
HtmlReport must implement rowNotImplementedError không phải là StandardError, vì vậy rescue trần không bắt được ngoại lệ này. Nhờ đó, phương thức bị thiếu không bị xử lý chung làm mất dấu. Khi cần, hãy bắt ngoại lệ này theo tê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)Đầu ra:
caught by name: missing step
falseBên cạnh các phương thức trừu tượng, một mẫu có thể cung cấp các phương thức móc: những bước có giá trị mặc định mà các lớp con có thể ghi đè. footer ở trên là một móc; một phương thức có câu trả lời có hoặc không như include_total? cũng vậy:
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: câu trả lời mặc định
false
end
endThử thách
DễHoàn thiện các lớp (class) báo cáo. Report#render(items) trả về dòng tiêu đề, một row cho mỗi mục và footer, nối với nhau bằng ký tự xuống dòng. header và row(item) là các phương thức trừu tượng: chúng phát sinh NotImplementedError với HtmlReport must implement row (tên lớp và phương thức). footer là một hook trả về end of report. CsvReport có dòng tiêu đề name,qty và các dòng dữ liệu pen,3. TextReport có dòng tiêu đề NAME QTY, các dòng dữ liệu có tên được đệm cho đủ 8 ký tự (pen 3) và dòng cuối 2 items. HtmlReport chỉ định nghĩa dòng tiêu đề [table].
Code được cung cấp đọc loại báo cáo từ dòng đầu tiên và các mục từ những dòng theo định dạng name qty, sau đó in ra render hoặc thông báo lỗi.
Code của bạn nằm trong các tệp report.rb, csv_report.rb, text_report.rb và html_report.rb. main.rb chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
require_relative 'report'
require_relative 'csv_report'
require_relative 'text_report'
require_relative 'html_report'
# Đoạn code đầu vào/đầu ra đã được cung cấp: giữ nguyê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
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Lớp và đối tượng
Làm việc với tệpĐịnh nghĩa lớpBiến instancePhương thức và selfto_s và inspectÔn tập: thẻ thư viện4Tính đóng gói
Phương thức riêng tưPhương thức được bảo vệPhương thức thiết lập riêng tưBảo vệ trạng tháiÔn tập: máy bán hàng tự động7Tính đa hình và duck typing
Tính đa hìnhDuck typingPhương thức trừu tượngcase và lớpÔn tập: phương thức thanh toán2Phương thức truy cập và self
Phương thức đọc và ghiPhương thức gán tùy chỉnhself trong phương thứcĐịnh danh và tính bằng nhauÔn tập: Danh sách liên hệTự luyện tập: Trình biên dịch Ruby online