الأساليب المجردة
جزء من قسم البرمجة كائنية التوجه في رحلة 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 rowNotImplementedError ليس 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إلى جانب الأساليب المجرّدة، يمكن للقالب أن يوفّر أساليب hook: وهي خطوات ذات سلوك افتراضي قد تتجاوزه الفئات الفرعية. يُعدّ footer أعلاه أحد أساليب hook؛ وكذلك أسلوب بنعم أو لا مثل 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? # hook: الإجابة الافتراضية
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 عبر الإنترنت