[英]How to resolve ruby module/mixin method conflict
在下面的代碼中, A
繼承了F
,后者繼承了E
,因此在A
實例上調用initialize
調用A#initialize
,它優先於E#initialize
和F#initialize
。
module E
def initialize(e)
@e = e
end
def e
@e
end
end
module F
def initialize(f)
@f = f
end
def f
@f
end
end
class A
include E
include F
def initialize(e, f)
# ...
end
end
我需要在A#initialize
的方法體內同時引用E#initialize
和F#initialize
,分別將e
和f
用作參數,以便得到以下結果:
a = A.new("foo", "bar")
a.e # => "foo"
a.f # => "bar"
有沒有辦法引用這些方法?
您遇到的問題是Ruby中沒有多重繼承。 因此,將模塊作為祖先插入,而使F#initialize
覆蓋E#initialize
。 如您所見,使用super(f)
可以很容易地訪問F#initialize
。 但是另一個需要黑客才能訪問:我們可以直接從模塊中選擇initialize
方法,因為它是祖先; 然后將其綁定到當前對象並運行它。
def initialize(e, f)
E.instance_method(:initialize).bind(self).call(e)
F.instance_method(:initialize).bind(self).call(f) # equivalent to super(f)
end
但是,我不建議這樣做。 如果您需要運行多個初始化程序,那么最好使用組合而不是繼承(要清楚, include
是繼承)。
您可以為此使用Method#super_method 。
module E
def initialize(e)
@e = e
end
def e
@e
end
end
module F
def initialize(f)
@f = f
end
def f
@f
end
end
class A
include E
include F
def initialize(e, f)
select_initialize(E).call e
select_initialize(F).call f
end
private
def select_initialize(mod)
self.class.
ancestors.
index(mod).
times.
reduce(method(:initialize)) { |m,_| m.super_method }
end
end
puts A.new("E", "F").f
#=> F
puts A.new("E", "F").e
#=> E
注意:
A.ancestors
#=> [A, F, E, Object, Kernel, BasicObject]
另請參見Module#ancestors , Array#index , Integer#times , Enumerable#reduce (aka inject
), Object#method和Method#call 。
E
和F
當然可以包含該類實例所需的其他實例方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.