Полиморфизм
Часть раздела Объектно-ориентированное программирование путешествия по 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Повторение — читательский билет4Инкапсуляция
Приватные методыЗащищённые методыПриватные сеттерыЗащита состоянияПовторение — торговый автомат7Полиморфизм и утиная типизация
ПолиморфизмУтиная типизацияАбстрактные методыcase и классыПовторение — способы оплаты10Шаблоны проектирования, часть 2
Делегирование с помощью ForwardableШаблон декоратораШаблон строителяШаблон состояния2Аксессоры и self
Чтение и записьПользовательские сеттерыself в методахИдентичность и равенствоПовторение — список контактов5Наследование
ПодклассыПереопределение методовВызов superis_a? и предкиПовторение — расчёт зарплаты сотрудников8Специальные методы
Равенство и хешированиеМетоды операторовИндексация и добавлениеПользовательские коллекцииПовторение — дроби11Проект: Управление библиотекой
Книги и читателиВыдача книг3Методы и переменные классов
Методы классовПеременные экземпляра классаКонстантыФабричные методыПовторение — коды купонов6Модули и примеси
Модули и includeРасширение объектовМодуль ComparableМодуль EnumerableПовторение — спортивная лига9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Онлайн-компилятор Ruby