Делегирование с помощью Forwardable
Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 46 из 57.
Делегирование означает, что объект передаёт часть своей работы объекту, который он содержит, вместо наследования от него. Плейлист, содержащий массив песен, безопаснее плейлиста, являющегося массивом, поскольку внешний код получает доступ только к тем методам, которые вы решите передать:
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Вывод:
2
IntroПисать каждый метод перенаправления вручную утомительно. Стандартная библиотека Forwardable делает это: extend Forwardable, затем def_delegators :@songs, :size, :first перенаправляет эти вызовы объекту в @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?Вывод:
2 Intro Dune
true
falsedef_delegator :@songs, :push, :add перенаправляет один метод под новым именем. Объект сохраняет полный контроль над всем, что он не перенаправляет, например над delete или 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)Результат:
a
1
falseПредпочитайте делегирование («имеет») в тех случаях, когда классу нужна лишь часть поведения другого класса. Наследование от Array сделало бы доступными десятки методов, таких как clear и delete_at, которые могли бы нарушить правила плейлиста:
class Playlist < Array # каждый метод Array является публичным, включая clear
end
class Playlist # публичным является только то, что вы перенаправляете
extend Forwardable
def_delegators :@songs, :size, :each
endЗадание
ЛегкоЗавершите класс Playlist с помощью Forwardable. Он хранит песни, каждая из которых представляет собой пару [title, seconds], в @songs. Передайте методы size, empty? и first с помощью def_delegators, а метод push передайте под именем add с помощью def_delegator. Его собственный метод duration возвращает общую продолжительность в формате m:ss, а titles возвращает названия, объединённые строкой , .
Предоставленный код добавляет песню для каждой входной строки (title,seconds) с помощью add, а затем выводит размер, название первой песни, названия песен, продолжительность и информацию о том, отвечает ли плейлист на clear.
Ваш код должен находиться в playlist.rb. В main.rb находится предоставленный код ввода/вывода, и его нельзя изменять.
Попробуйте сами
require_relative 'playlist'
# Предоставленный код ввода/вывода: оставьте его как есть
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)}"
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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