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 # clear를 포함한 모든 Array 메서드는 public이다
end
class Playlist # 위임한 것만 public이다
extend Forwardable
def_delegators :@songs, :size, :each
end챌린지
쉬움Forwardable을 사용해 Playlist 클래스를 완성하세요. 이 클래스는 @songs에 노래를 저장하며, 각 노래는 [title, seconds] 쌍입니다. 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 컴파일러