Polimorfismo
Parte de la sección Programación orientada a objetos del Journey de Ruby de Coddy. Lección 32 de 57.
Polimorfismo significa que una llamada a un método funciona con objetos de distintas clases y que cada objeto responde a su manera. El código que recorre las formas llama a area en cada una sin preguntar qué tipo de forma es:
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))Salida:
circle 3.14
square 9.00
total 12.14Sin polimorfismo, quien realiza la llamada tiene que comprobar el tipo de cada objeto y repetir esa comprobación allí donde la diferencia sea relevante. Con él, la diferencia vive dentro de cada clase:
# sin polimorfismo
case shape.kind
when "circle" then 3.14159 * shape.r ** 2
when "square" then shape.side ** 2
end
# con polimorfismo
shape.areaAgregar un nuevo tipo de objeto después no requiere ningún cambio en el código que realiza la llamada: una nueva subclase con su propio area funciona en todos los bucles que ya existen:
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 }Salida:
area 4
area 6to_s es el ejemplo cotidiano: puts lo invoca en cualquier objeto, y cada clase responde de manera diferente. Tus clases también participan definiendo su propio to_s:
class Coin
def to_s
"a coin"
end
end
[42, "text", nil, [1, 2], Coin.new].each { |x| puts "[#{x}]" }Salida:
[42]
[text]
[]
[[1, 2]]
[a coin]Desafío
FácilCompleta las formas. Shape#to_s devuelve circle: 3.14, el nombre de la clase en minúsculas y el área con dos decimales, y cada subclase proporciona area: Circle.new(r) (usa 3.14159 para pi), Rectangle.new(w, h) y Triangle.new(base, height).
El código proporcionado lee líneas circle 1, rectangle 2 3 o triangle 4 5, imprime cada forma, después total: 22.14 y largest: rectangle: 6.00, trabajando únicamente con to_s y area.
Tu código va en shape.rb, circle.rb, rectangle.rb y triangle.rb. main.rb contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
require_relative 'shape'
require_relative 'circle'
require_relative 'rectangle'
require_relative 'triangle'
# Código de entrada/salida suministrado: mantenlo como está
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)}"
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Clases y objetos
Trabajar con archivosDefinir clasesVariables de instanciaMétodos y selfto_s e inspectRepaso: tarjeta de biblioteca4Encapsulación
Métodos privadosMétodos protegidosAsignadores privadosProtección del estadoRepaso: máquina expendedora7Polimorfismo y tipado pato
PolimorfismoTipado patoMétodos abstractoscase y clasesRepaso: métodos de pago2Accesores y self
Lectores y escritoresSetters personalizadosself en los métodosIdentidad e igualdadRepaso: lista de contactos5Herencia
SubclasesSobrescritura de métodosLlamar a superis_a? y ancestrosRepaso - Nómina del personal8Métodos especiales
Igualdad y hashMétodos de operadoresIndexación y adiciónColecciones personalizadasRepaso: fracciones11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Compilador de Ruby online