تعدد الأشكال
جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 32 من 57.
تعدد الأشكال يعني أن استدعاءً واحدًا لأسلوب يعمل مع كائنات من فئات مختلفة، وأن كل كائن يستجيب بطريقته الخاصة. يستدعي الكود الذي يكرّر على الأشكال area لكل شكل دون أن يسأل عن نوع الشكل:
class Shape
def to_s
format("%s %.2f", self.class.name.downcase, area)
end
end
class Circle < Shape
def initialize(r)
@r = r
end
def area
3.14159 * @r * @r
end
end
class Square < Shape
def initialize(side)
@side = side
end
def area
@side * @side
end
end
shapes = [Circle.new(1), Square.new(3)]
shapes.each { |s| puts s }
puts format("total %.2f", shapes.sum(&:area))الناتج:
circle 3.14
square 9.00
total 12.14من دون تعدد الأشكال، يتعين على المستدعي التحقق من نوع كل كائن وتكرار هذا التحقق أينما كان الاختلاف مهمًا. أما معه، فيعيش الاختلاف داخل كل فئة:
# بدون تعدد الأشكال
case shape.kind
when "circle" then 3.14159 * shape.r ** 2
when "square" then shape.side ** 2
end
# مع تعدد الأشكال
shape.areaإضافة نوع جديد من الكائنات لا تتطلب بعد ذلك أي تغيير في الشيفرة المستدعية: فالفئة الفرعية الجديدة التي تمتلك area الخاص بها تعمل في كل حلقة موجودة مسبقًا:
class Shape
def describe
"area #{area}"
end
end
class Square < Shape
def area
4
end
end
class Triangle < Shape
def area
6
end
end
[Square.new, Triangle.new].each { |s| puts s.describe }الناتج:
area 4
area 6to_s هو المثال اليومي: تستدعيه puts على أي كائن، وتجيب كل فئة بطريقة مختلفة. وتنضم فئاتك إلى ذلك من خلال تعريف to_s الخاص بها:
class Coin
def to_s
"a coin"
end
end
[42, "text", nil, [1, 2], Coin.new].each { |x| puts "[#{x}]" }الناتج:
[42]
[text]
[]
[[1, 2]]
[a coin]التحدي
سهلأكمل الأصناف. تُرجع Shape#to_s القيمة circle: 3.14، أي اسم الصنف بأحرف صغيرة والمساحة بمنزلتين عشريتين، ويوفّر كل صنف فرعي area: Circle.new(r) (استخدم 3.14159 للعدد π)، وRectangle.new(w, h) وTriangle.new(base, height).
يقرأ الكود المزوَّد أسطرًا مثل circle 1 أو rectangle 2 3 أو triangle 4 5، ويطبع كل شكل، ثم total: 22.14 وlargest: rectangle: 6.00، مع العمل باستخدام to_s وarea فقط.
ضع الكود الخاص بك في shape.rb وcircle.rb وrectangle.rb وtriangle.rb. يحتوي main.rb على كود الإدخال/الإخراج المزوَّد، ولا يمكن تعديله.
جرّب بنفسك
require_relative 'shape'
require_relative 'circle'
require_relative 'rectangle'
require_relative 'triangle'
# كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
input = []
while (line = gets)
input << line.chomp
end
kinds = { "circle" => Circle, "rectangle" => Rectangle, "triangle" => Triangle }
shapes = input.map do |line|
kind, *numbers = line.split
kinds[kind].new(*numbers.map(&:to_f))
end
shapes.each { |s| puts s }
puts format("total: %.2f", shapes.sum(&:area))
puts "largest: #{shapes.max_by(&:area)}"
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتمتغيرات النسخةالأساليب و selfto_s و inspectمراجعة - بطاقة المكتبة7تعدد الأشكال والكتابة بأسلوب البطة
تعدد الأشكالالكتابة بأسلوب البطةالأساليب المجردةالحالات والفئاتمراجعة - طرق الدفع3أساليب ومتغيرات الأصناف
أساليب الأصنافمتغيرات كائنات الأصنافالثوابتأساليب الإنشاءمراجعة - رموز القسائمتدرّب بنفسك: مترجم Ruby عبر الإنترنت