Menu
CoddyTech

Polimorfismo

Fa parte della sezione Programmazione orientata agli oggetti del percorso Ruby di Coddy. Lezione 32 di 57.

Polimorfismo significa che una chiamata di metodo funziona su oggetti di classi diverse e che ogni oggetto risponde a modo proprio. Il codice che scorre le forme chiama area su ciascuna senza chiedere di che tipo di forma si tratti:

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))

Output:

circle 3.14
square 9.00
total 12.14

Senza polimorfismo, chi chiama deve controllare il tipo di ogni oggetto e ripetere quel controllo ovunque la differenza sia rilevante. Con il polimorfismo, la differenza risiede all'interno di ogni classe:

# senza polimorfismo
case shape.kind
when "circle" then 3.14159 * shape.r ** 2
when "square" then shape.side ** 2
end

# con polimorfismo
shape.area

Aggiungere un nuovo tipo di oggetto non richiede quindi modifiche al codice chiamante: una nuova sottoclasse con il proprio area funziona in ogni ciclo già esistente:

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 }

Output:

area 4
area 6

to_s è l'esempio di uso quotidiano: puts lo chiama su qualsiasi oggetto e ogni classe risponde in modo diverso. Anche le tue classi partecipano definendo il proprio to_s:

class Coin
  def to_s
    "a coin"
  end
end

[42, "text", nil, [1, 2], Coin.new].each { |x| puts "[#{x}]" }

Output:

[42]
[text]
[]
[[1, 2]]
[a coin]
challenge icon

Sfida

Facile

Completa le forme. Shape#to_s restituisce circle: 3.14, il nome della classe in minuscolo e l’area con due cifre decimali, e ogni sottoclasse fornisce area: Circle.new(r) (usa 3.14159 per pi), Rectangle.new(w, h) e Triangle.new(base, height).

Il codice fornito legge righe circle 1, rectangle 2 3 o triangle 4 5, stampa ogni forma, poi total: 22.14 e largest: rectangle: 6.00, usando solo to_s e area.

Il tuo codice va in shape.rb, circle.rb, rectangle.rb e triangle.rb. main.rb contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

require_relative 'shape'
require_relative 'circle'
require_relative 'rectangle'
require_relative 'triangle'

# Supplied input/output code: keep it as it is
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 iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Ruby online