扩展对象
本课属于 Coddy Ruby 学习旅程的“面向对象编程”单元。第 28 课,共 57 课。
extend 会将模块的方法添加到一个对象,而不是所有实例。扩展类会将这些方法添加到类对象中,因此它们会成为类方法:
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输出:
Dog has 2 methods与 extend 一起使用的模块可以在类的实例变量中保存状态。每个扩展该模块的类都会获得自己的副本,作为类实例变量:
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}"输出:
2 1extend 也可以作用于单个对象。只有该对象会获得这些方法;同一个类的其他实例保持不变,并且只有扩展后的对象的 is_a? 才是 true:
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)输出:
car is shining
true
false这两个关键字会将同一模块的方法放在不同的位置。include 会将它们变成类的实例方法,extend 会将它们变成被扩展的那个对象的方法:
class Order
include Printable # order.print_me (每个实例)
extend Counted # Order.record (类本身)
end
item.extend(Shiny) # item.polish (只有这个对象)挑战
简单完成模块 Registry,类会使用 extend 来扩展它。register(name) 会将一个名称添加到该类自己的列表中,列表保存在 @entries 中(首次使用时创建),并返回 Plugin registered x;如果名称已经在列表中,则返回 Plugin already has x。entries 返回列表,count 返回列表的大小。Plugin 和 Theme 都会扩展 Registry,并各自维护独立的列表。
提供的代码会读取 plugin name 或 theme name 格式的行,在对应的类上调用 register,并打印返回内容。最后,它会打印 plugins: a, b (2) 和 themes: ...;如果列表为空,则打印 none (0)。
你的代码写在 registry.rb、plugin.rb 和 theme.rb 中。main.rb 包含提供的输入/输出代码,不能编辑。
亲手试试
require_relative 'registry'
require_relative 'plugin'
require_relative 'theme'
# 提供的输入和输出代码:保持原样
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
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Ruby 在线编译器