我有以下课程:
class Alphabet
attr_reader :letter_freqs, :statistic_letter
def initialize(lang)
@lang = lang
case lang
when :en
@alphabet = ('A'..'Z').to_a
@letter_freqs = { ... }
when :ru
@alphabet = ('А'..'Я').to_a.insert(6, 'Ё')
@letter_freqs = { ... }
...
end
@statistic_letter = @letter_freqs.max_by { |k, v| v }[0]
end
end
foo = Alphabet.new(:en)
此处的中心成员是@alphabet
。
我想让它成为一种容器类来直接调用Array方法,比如
foo[i]
foo.include?
而非明确访问@alphabet
:
foo.alphabet[i]
foo.alphabet.include?
我知道我可以定义很多方法,比如
def [](i)
@alphabet[i]
end
但我正在寻找一种“继承”它们的正确方法。
答案 0 :(得分:10)
您可以使用Forwardable
(它包含在Ruby标准库中):
require 'forwardable'
class Alphabet
extend Forwardable
def_delegators :@alphabet, :[], :include?
def initialize
@alphabet = ('A'..'Z').to_a
end
end
foo = Alphabet.new
p foo[0] #=> "A"
p foo.include? 'ç' #=> false
如果您希望委派您的课程未定义的所有方法,您可以使用SimpleDelegator
(也在标准库中);它允许您将实例未响应的所有方法委托给__setobj__
指定的对象:
require 'delegate'
class Alphabet < SimpleDelegator
def initialize
@alphabet = ('A'..'Z').to_a
__setobj__(@alphabet)
end
def index
'This is not @alphabet.index'
end
end
foo = Alphabet.new
p foo[0] #=> "A"
p foo.include? 'ç' #=> false
p foo.index #=> "This is not @alphabet.index"
当委托不需要是动态的时,您可以将主类安排为DelegateClass
的子类,传递要作为参数委派的类的名称并调用super
传递要在主类的#initialize
方法中委派的对象:
class Alphabet < DelegateClass(Array)
def initialize
@alphabet = ('A'..'Z').to_a
super(@alphabet)
end
有关Ruby here
中的委托设计模式的更多信息答案 1 :(得分:2)
您可以扩展Forwardable模块:
class Alphabet
require 'forwardable'
extend Forwardable
attr_accessor :alphabet
def initialize
@alphabet = [1,2,3]
end
def_delegator :@alphabet, :[], :include?
end
然后你可以这样做:
alpha = Alphabet.new
alpha[1]==hey.alphabet[1]
=> true
警告:强>
不要尝试委托所有方法(不知道是否可能),因为它们可能共享一些相同的方法名称,例如class
,这可能会造成混乱。
答案 2 :(得分:0)
在Ruby中,您可以像这样扩展对象。
class Array
def second
self[1]
end
end
[1, 2, 3, 4, 5].second
# => 2
或者如果你想继承一个数组。
class Foo < Array
def second
self[1]
end
end
[1, 2, 3, 4, 5].include? 2
# => true
[1, 2, 3, 4, 5].second
# => 2
如果您有任何其他问题,请发表评论,我会更新答案。