Menu
CoddyTech

Delegation mit Forwardable

Teil des Abschnitts Objektorientierte Programmierung der Ruby-Journey von Coddy. Lektion 46 von 57.

Delegation bedeutet, dass ein Objekt einen Teil seiner Arbeit an ein Objekt überträgt, das es enthält, anstatt von diesem zu erben. Eine Playlist, die ein Array von Songs enthält, ist sicherer als eine, die selbst ein Array ist, denn externer Code erhält nur Zugriff auf die Methoden, die du weiterleitest:

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

Ausgabe:

2
Intro

Jede Weiterleitungsmethode von Hand zu schreiben, ist repetitiv. Die Standardbibliothek erledigt das mit Forwardable: Mit extend Forwardable und anschließend def_delegators :@songs, :size, :first werden diese Aufrufe an das Objekt in @songs weitergeleitet:

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?

Ausgabe:

2 Intro Dune
true
false

def_delegator :@songs, :push, :add leitet eine Methode unter einem neuen Namen weiter. Das Objekt behält die volle Kontrolle über alles, was es nicht weiterleitet, zum Beispiel delete oder 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)

Ausgabe:

a
1
false

Bevorzuge Delegation („hat ein“), wenn eine Klasse nur einen Teil des Verhaltens einer anderen Klasse benötigt. Die Ableitung von Array würde Dutzende von Methoden wie clear und delete_at verfügbar machen, die die Regeln der Playlist verletzen könnten:

class Playlist < Array      # jede Methode von Array ist öffentlich, einschließlich clear
end

class Playlist              # nur das, was du weiterleitest, ist öffentlich
  extend Forwardable
  def_delegators :@songs, :size, :each
end
challenge icon

Aufgabe

Einfach

Vervollständige die Klasse Playlist mit Forwardable. Sie enthält Songs, jeweils ein Paar aus [title, seconds], in @songs. Delegiere size, empty? und first mit def_delegators weiter und delegiere push unter dem Namen add mit def_delegator. Ihre eigene Methode duration gibt die Gesamtdauer als m:ss zurück, und titles gibt die Titel zurück, verbunden durch , .

Der bereitgestellte Code fügt für jede Eingabezeile (title,seconds) mit add einen Song hinzu und gibt dann die Anzahl, den ersten Titel, die Titel, die Dauer und aus, ob die Playlist auf clear reagiert.

Dein Code gehört in playlist.rb. main.rb enthält den bereitgestellten Ein-/Ausgabecode und kann nicht bearbeitet werden.

Probier es selbst

require_relative 'playlist'

# Vorgegebener Ein-/Ausgabecode: unverändert lassen
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 iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Ruby-Compiler