Ủy quyền với Forwardable
Thuộc phần Lập trình hướng đối tượng trong hành trình Ruby của Coddy. Bài học 46 trên 57.
Ủy quyền (delegation) nghĩa là một đối tượng giao một phần công việc cho đối tượng mà nó nắm giữ, thay vì kế thừa từ đối tượng đó. Một danh sách phát có mảng bài hát sẽ an toàn hơn một danh sách phát là mảng, vì code bên ngoài chỉ có thể dùng những phương thức bạn chọn chuyển tiếp:
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Đầu ra:
2
IntroViết từng phương thức chuyển tiếp bằng tay rất lặp lại. Thư viện chuẩn có Forwardable để làm việc đó: extend Forwardable, sau đó def_delegators :@songs, :size, :first chuyển tiếp các lệnh gọi đó đến đối tượng trong @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?Đầu ra:
2 Intro Dune
true
falsedef_delegator :@songs, :push, :add chuyển tiếp một phương thức bằng một tên mới. Đối tượng vẫn toàn quyền kiểm soát mọi thứ mà nó không chuyển tiếp, chẳng hạn như delete hoặc 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)Đầu ra:
a
1
falseƯu tiên ủy quyền («có một») khi một lớp chỉ cần một phần hành vi của lớp khác. Kế thừa từ Array sẽ để lộ hàng chục phương thức, chẳng hạn như clear và delete_at, có thể phá vỡ các quy tắc của danh sách phát:
class Playlist < Array # Mọi phương thức (method) của Array đều là public, kể cả clear
end
class Playlist # Chỉ những gì bạn chuyển tiếp mới là public
extend Forwardable
def_delegators :@songs, :size, :each
endThử thách
DễHoàn thiện lớp Playlist bằng Forwardable. Lớp này lưu các bài hát, mỗi bài là một cặp [title, seconds], trong @songs. Chuyển tiếp các phương thức size, empty? và first bằng def_delegators, rồi chuyển tiếp push dưới tên add bằng def_delegator. Phương thức riêng duration trả về tổng thời lượng theo định dạng m:ss, còn titles trả về các tiêu đề được nối bằng , .
Code được cung cấp thêm một bài hát cho mỗi dòng đầu vào (title,seconds) bằng add, rồi in ra số bài hát, tiêu đề bài đầu tiên, các tiêu đề, thời lượng và thông tin danh sách phát có phản hồi với clear hay không.
Code của bạn nằm trong playlist.rb. main.rb chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
require_relative 'playlist'
# Đoạn code đầu vào/đầu ra đã được cung cấp: giữ nguyên
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)}"
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Lớp và đối tượng
Làm việc với tệpĐịnh nghĩa lớpBiến instancePhương thức và selfto_s và inspectÔn tập: thẻ thư viện4Tính đóng gói
Phương thức riêng tưPhương thức được bảo vệPhương thức thiết lập riêng tưBảo vệ trạng tháiÔn tập: máy bán hàng tự động7Tính đa hình và duck typing
Tính đa hìnhDuck typingPhương thức trừu tượngcase và lớpÔn tập: phương thức thanh toán2Phương thức truy cập và self
Phương thức đọc và ghiPhương thức gán tùy chỉnhself trong phương thứcĐịnh danh và tính bằng nhauÔn tập: Danh sách liên hệTự luyện tập: Trình biên dịch Ruby online