Menu
CoddyTech

Mở rộng đối tượng

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 28 trên 57.

extend thêm các phương thức của một module vào một đối tượng thay vì thêm vào tất cả các instance. Khi mở rộng một lớp, các phương thức được thêm vào đối tượng lớp, vì vậy chúng trở thành phương thức của lớp:

module Describable
  def describe
    "#{name} has #{instance_methods(false).size} methods"
  end
end

class Dog
  extend Describable

  def bark
    "Woof"
  end

  def sit
    "sits"
  end
end

puts Dog.describe

Đầu ra:

Dog has 2 methods

Một module được dùng với extend có thể lưu trạng thái trong các biến instance của lớp. Mỗi lớp kế thừa module đó sẽ có một bản sao riêng, dưới dạng biến instance của lớp:

module Counted
  def created
    @created ||= 0
  end

  def record
    @created = created + 1
  end
end

class Order
  extend Counted
end

class Invoice
  extend Counted
end

Order.record
Order.record
Invoice.record
puts "#{Order.created} #{Invoice.created}"

Đầu ra:

2 1

extend cũng hoạt động với một đối tượng đơn lẻ. Chỉ đối tượng đó có thêm các phương thức; các instance khác thuộc lớp đó vẫn không thay đổi, và is_a? trả về true chỉ với đối tượng được mở rộng:

module Shiny
  def polish
    "#{self} is shining"
  end
end

a = "car"
b = "bike"
a.extend(Shiny)
puts a.polish
puts a.is_a?(Shiny)
puts b.respond_to?(:polish)

Đầu ra:

car is shining
true
false

Hai từ khóa này đặt các phương thức của cùng một module vào những nơi khác nhau. include biến chúng thành phương thức instance của một lớp, còn extend biến chúng thành phương thức của chính đối tượng được mở rộng:

class Order
  include Printable    # order.print_me       (mọi instance)
  extend Counted       # Order.record         (chính lớp đó)
end

item.extend(Shiny)     # item.polish          (chỉ đối tượng này)
challenge icon

Thử thách

Dễ

Hoàn thiện module Registry, các lớp sử dụng module này với extend. register(name) thêm một tên vào danh sách riêng của lớp, lưu trong @entries (được tạo khi dùng lần đầu), và trả về Plugin registered x; nếu tên đã có trong danh sách, hàm trả về Plugin already has x. entries trả về danh sách, còn count trả về kích thước của danh sách. Cả Plugin và Theme đều mở rộng Registry và giữ danh sách riêng.

Code được cung cấp đọc các dòng plugin name hoặc theme name, gọi register trên lớp tương ứng và in câu trả lời. Cuối cùng, chương trình in plugins: a, b (2) và themes: ..., hoặc none (0) nếu danh sách trống.

Code của bạn nằm trong registry.rb, plugin.rb và theme.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 'registry'
require_relative 'plugin'
require_relative 'theme'

# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
input = []
while (line = gets)
  input << line.chomp
end
input.each do |line|
  kind, name = line.split
  target = kind == "plugin" ? Plugin : Theme
  puts target.register(name)
end
[["plugins", Plugin], ["themes", Theme]].each do |label, klass|
  list = klass.entries.empty? ? "none" : klass.entries.join(", ")
  puts "#{label}: #{list} (#{klass.count})"
end
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch Ruby online