الأساليب المجردة
جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 34 من 57.
يمكن للصنف الأب تحديد خطوات خوارزمية وترك بعض الخطوات لأصنافه الفرعية. هذا هو نمط طريقة القالب: تكون 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التحدي
سهلأكمل أصناف التقارير. تعيد Report#render(items) سطر الترويسة، وسطرًا واحدًا من row لكل عنصر، وfooter، مع وصلها بأسطر جديدة. إن header وrow(item) مجردتان: ترفعان NotImplementedError مع HtmlReport must implement row (اسم الصنف والطريقة). إن 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
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتمتغيرات النسخةالأساليب و selfto_s و inspectمراجعة - بطاقة المكتبة7تعدد الأشكال والكتابة بأسلوب البطة
تعدد الأشكالالكتابة بأسلوب البطةالأساليب المجردةالحالات والفئاتمراجعة - طرق الدفع3أساليب ومتغيرات الأصناف
أساليب الأصنافمتغيرات كائنات الأصنافالثوابتأساليب الإنشاءمراجعة - رموز القسائمتدرّب بنفسك: مترجم Ruby عبر الإنترنت