模块A
依赖于模块B
,而类C
依赖于模块A
和B
。如果我将A
和B
包含到C
中,这可行,但我不喜欢A
依赖于必须与之混合的另一个模块的事实它的工作原理。
在这种情况下混合模块的“正确”方法是什么? A
本身应该B
混合吗?如果C
也直接使用B
该怎么办?
module B
def g
12
end
end
module A
def f
2 * g
end
end
class C
include A, B
def h
3 * f
end
end
答案 0 :(得分:2)
您可以覆盖Module#included
module A
def self.included(base)
base.class_eval do
include B
end
end
end
完成后,A就在A之后。
答案 1 :(得分:1)
冗余地编写include
没有错。如果A
和C
都依赖于B
,则B
和A
中都包含C
。
module B
def g; 12 end
def i; 7 end
end
module A
include B
def f; 2 * g end
end
class C
include A, B
def h; 3 * f * i end
end
如果C
不依赖于B
,请仅在B
中加入A
。
module B
def g; 12 end
end
module A
include B
def f; 2 * g end
end
class C
include A
def h; 3 * f end
end
答案 2 :(得分:0)
模块A的方法依赖于模块B中的功能。[...]在这种情况下,在模块中混合的“正确”方法是什么? B本身应该混合吗?如果C也直接使用B怎么办?
你没有多少选择。应根据A,B和C之间的关系选择其中的每一个。
第一个是声明一个模块D
,它将定义A
和B
之间的共享功能。通过这种方式,您可以轻松地将D
与A
和B
混合,而无需担心太多:
module D; ...; end
module A; include D; ...; end
module B; include D; ...; end
我能想到的另一个是将A
和B
转换为类以便使用继承。当具有两个具有强依赖关系的类时,继承是好的。如果A
使用的功能足够强,您一定要选择以下功能:
class B; ...; end
class A < B; ...; end
class C < A; ...; end
答案 3 :(得分:0)
因为在你的情况下,你没有具有相同名称的重写方法,无论你混合使用什么方式,实例方法都将按预期一起工作。你只需要确保它们真的混合在一起:
[ A, B ].all? { |m| C.kind_of? m } # must be true
所以,在你的情况下,你是否这样做无关紧要
class C; include A, B; end
或者
class C; include B, A; end
或者
module B; include A end
class C; include B end
或者
module A; include B end
class C; include A end
提醒您注意的一点是,这不起作用:
class C; include A; end # including the module A first
module A; include B end # and trying to remix it after
c = C.new # does not work
c.h # raises NoMethodError
# Modules have to have finished mixing when they are included.
这就是全部!
答案 4 :(得分:0)
如果A依赖于B并且您的模块仅定义实例方法,那么在A中包含B我没有看到任何错误。如果您需要类方法,可能需要考虑http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
module B
def method_b
"B instance method"
end
end
module A
include B
def method_a
"A instance method is using #{method_b}"
end
end
class Klass
include A
end
k = Klass.new
puts k.method_a #=> A instance method is using B instance method
puts k.method_b #=> B instance method
puts k.class.ancestors.inspect #=> [Klass, A, B, Object, Kernel, BasicObject]