Menu
Coddy logo textTech

Delegazione con Forwardable

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

La delega significa che un oggetto affida parte del proprio lavoro a un oggetto che contiene, invece di ereditare da esso. Una playlist che contiene un array di brani è più sicura di una che è un array, perché il codice esterno può usare solo i metodi che scegli di inoltrare:

class Playlist
  def initialize
    @songs = []
  end

  def add(song)
    @songs << song
    self
  end

  def size
    @songs.size
  end

  def first
    @songs.first
  end
end

list = Playlist.new.add("Intro").add("Dune")
puts list.size
puts list.first

Output:

2
Intro

Scrivere a mano ogni metodo di inoltro è ripetitivo. La libreria standard Forwardable lo fa al posto tuo: extend Forwardable, poi def_delegators :@songs, :size, :first inoltra queste chiamate all’oggetto in @songs:

require 'forwardable'

class Playlist
  extend Forwardable
  def_delegators :@songs, :size, :first, :last, :empty?, :include?

  def initialize
    @songs = []
  end

  def add(song)
    @songs << song
    self
  end
end

list = Playlist.new.add("Intro").add("Dune")
puts "#{list.size} #{list.first} #{list.last}"
puts list.include?("Dune")
puts list.empty?

Output:

2 Intro Dune
true
false

def_delegator :@songs, :push, :add inoltra un metodo con un nuovo nome. L’oggetto mantiene il pieno controllo di tutto ciò che non inoltra, ad esempio delete o clear:

require 'forwardable'

class Queue2
  extend Forwardable
  def_delegator :@jobs, :push, :enqueue
  def_delegator :@jobs, :shift, :next_job
  def_delegators :@jobs, :size

  def initialize
    @jobs = []
  end
end

q = Queue2.new
q.enqueue("a")
q.enqueue("b")
puts q.next_job
puts q.size
puts q.respond_to?(:clear)

Output:

a
1
false

Preferisci la delega ("ha un") quando una classe ha bisogno solo di una parte del comportamento di un'altra classe. Ereditare da Array esporrebbe decine di metodi, come clear e delete_at, che potrebbero violare le regole della playlist:

class Playlist < Array      # tutti i metodi di Array sono pubblici, incluso clear
end

class Playlist              # solo ciò che inoltri è pubblico
  extend Forwardable
  def_delegators :@songs, :size, :each
end
challenge icon

Sfida

Facile

Completa la classe Playlist con Forwardable. Contiene brani, ciascuno una coppia [title, seconds], in @songs. Delega size, empty? e first con def_delegators, e delega push con il nome add usando def_delegator. Il suo metodo duration restituisce la durata totale nel formato m:ss, e titles restituisce i titoli uniti da , .

Il codice fornito aggiunge un brano per ogni riga di input (title,seconds) con add, poi stampa la dimensione, il primo titolo, i titoli, la durata e se la playlist risponde a clear.

Il tuo codice va in playlist.rb. main.rb contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

require_relative 'playlist'

# Código de entrada/salida proporcionado: mantenlo tal como está
input = []
while (line = gets)
  input << line.chomp
end
list = Playlist.new
input.each do |line|
  title, seconds = line.split(",")
  list.add([title, seconds.to_i])
end
puts "songs: #{list.size}"
puts "first: #{list.empty? ? "none" : list.first[0]}"
puts "titles: #{list.titles}"
puts "duration: #{list.duration}"
puts "can clear: #{list.respond_to?(:clear)}"
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