2

模块A依赖于模块B,类C依赖于模块AB. 如果我 includeABinto C,这是可行的,但我不喜欢A依赖另一个模块的事实,该模块必须与它一起混合才能工作。

在这种情况下,混合模块的“正确”方法是什么?应该自己A混合B吗?如果CB直接使用呢?

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
4

5 回答 5

2

您可以覆盖Module#included

module A
  def self.included(base)
    base.class_eval do
      include B
    end
  end
end

完成后,B 将包含在 A 之后。

于 2013-06-10T23:25:02.810 回答
1

include多余的写作并没有错。如果AandC都依赖于B,则包含BAandC中。

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,则只包含BA

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
于 2013-06-11T03:10:05.910 回答
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]
于 2013-06-11T02:09:11.710 回答
0

模块 A 有一个依赖于模块 B 中的功能的方法。 [...]。在这种情况下,混合模块的“正确”方法是什么?A 是否应该混入 B 本身?如果 C 也直接使用 B 怎么办?

你别无选择。应根据 A、B 和 C 之间的关系来选择其中的每一个。

第一个是声明一个模块,该模块D将定义 和 之间的共享A功能B。通过这种方式,您可以轻松地D与两者混合,AB无需过多担心:

module D; ...; end
module A; include D; ...; end
module B; include D; ...; end

我能想到的另一种方法是转换AB转换为类以使用继承。当有两个具有强依赖关系的类时,继承是好的。如果使用的功能A足够强大,你绝对应该选择这个:

class B; ...; end
class A < B; ...; end
class C < A; ...; end
于 2013-06-10T23:28:20.223 回答
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.

就这样!

于 2013-06-11T00:52:03.853 回答