2013-06-10 13 views
2

Модуль A полагается на модуль B, а класс C опирается на модули A и B. Если я включаю A и B в C, это работает, но мне не нравится тот факт, что A имеет зависимость от другого модуля, который необходимо смешивать вместе с ним для его работы.смешивание в модулях, которые зависят друг от друга?

Что такое «правильный» способ смешивания модулей в этой ситуации? Должно ли A mix в 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 

ответ

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 
+0

спасибо, это имеет смысл. – akonsu

2

Вы можете переопределить Module#included

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

Когда это будет сделано, B включается сразу после А.

+0

Это отличное решение, но имейте в виду, что порядок загрузки определяет, когда версия метода заканчивается на объекте, если А и В оба реализуют версии одного и того же метода! –

+0

Почему не просто 'base.include B'? –

0

Модуль А есть метод, который опирается на функциональные возможности найти в модуле 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 
+0

Какую версию Ruby вы используете? Я не могу понять, что вы используете ключевое слово import. –

+0

@BorisStitnicky, извините. Я имел в виду «включить». слишком много Python;) – Shoe

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. 

Это все!

0

Я не вижу ничего плохого, просто включив B внутри A, если 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] 
Смежные вопросы