Menu
Coddy logo textTech

פולימורפיזם

חלק מהיחידה תכנות מונחה עצמים במסלול ה-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 6

to_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]
challenge icon

אתגר

קל

השלימו את הצורות. 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)}"
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Ruby אונליין