Forwardable을 활용한 위임
Coddy Ruby 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 46번째.
위임은 객체가 다른 객체로부터 상속하는 대신, 자신이 보유한 객체에 작업의 일부를 넘기는 것을 의미합니다. 노래 배열인 플레이리스트보다 노래 배열을 포함하는 플레이리스트가 더 안전합니다. 외부 코드가 호출할 수 있는 것은 여러분이 전달하기로 선택한 메서드뿐이기 때문입니다:
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클래스에 다른 클래스 동작의 일부만 필요한 경우에는 상속("has a")보다 위임을 선호하세요. Array를 상속하면 clear와 delete_at 같은 수십 개의 메서드가 노출되어 플레이리스트의 규칙을 깨뜨릴 수 있습니다:
class Playlist < Array # 모든 Array 메서드가 public이며, clear도 포함됩니다
end
class Playlist # 전달한 것만 public입니다
extend Forwardable
def_delegators :@songs, :size, :each
end챌린지
쉬움Forwardable을 사용하여 Playlist 클래스를 완성하세요. 이 클래스는 각각 [title, seconds] 쌍인 곡들을 @songs에 저장합니다. def_delegators를 사용하여 size, empty? 및 first를 전달하고, def_delegator를 사용하여 push를 add라는 이름으로 전달하세요. 자체 메서드인 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)}"
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Ruby 컴파일러