2016-02-21 3 views
1

Я пишу модуль для обработки платежей на нашем веб-сайте.Ruby on Rails OOP не работает должным образом

# lib/payment/payment.rb 
module Payment 
    class Payment 
    # some payment handling 
    end 
end 

И я хочу отделить логику, определяющую причитающуюся сумму. Мы просто скажем, что мы платим за Car в качестве примера.

Теперь, я был под впечатлением, что это будет работать:

# lib/payment/car.rb 
module Payment 
    class Car < Payment 
    # builds amount for cars 
    end 
end 

Но даже в модуле оплаты, с Оплата :: Оплата определен, он бросает:

TypeError: superclass must be a Class (Module given) 

I Известно, что это решает проблему:

class Payment::Car < Payment::Payment 
    # stuff 
end 

Но мне любопытно, почему мое решение не работает.

+0

Может быть, 'lib/payment/payment.rb' должен быть' lib/payment.rb' и оставить остальное в папке 'lib/payment'? – fbelanger

+0

Нет ... Мне действительно интересно, чего я не хватает. – fbelanger

+0

Хорошо, так что это определенно связано с именованием модуля и класса Payment. Все предложения и комментарии оценены, спасибо! – fbelanger

ответ

2

Я думаю, вы точно прикрепили его в своем комментарии. Именование и модуля, и класса Payment является проблемой.

Если у вас есть

module Payment 
    class Car < Payment 
    end 
end 

пытается (автозагрузки при загрузке Car) для загрузки Payment. Первая константа, встречающаяся в дереве с именем Payment, является модулем, а не классом. Он не знает, что вы пытаетесь загрузить класс под названием Payment - поэтому он пытается использовать модуль Payment. Вот почему вы получаете полученную вами ошибку.

Когда вы

Payment::Car < Payment::Payment 

Ты explicitley говорят, что вы хотите, класс Payment, расположенный в модуле Payment, так что теперь автозагрузка может загрузить правильный Constant.

В качестве последующей мысли, кажется концептуально странно иметь Car унаследовать от Payment. Технически это работает. Но это не отражает реальный мир. Чтобы включить классы с поведением платежей, вы можете пойти по маршруту композиции. Таким образом, сделать модуль что-то вроде:

module Payments 
    module PaymentClassMethods 
    def some_method 
    end 
    def some_other_method 
    end 
    end 
end 

Затем сделайте

module Payments 
    class Car 
    extend PaymentClassMethods 
    end 
end 

Теперь Car не наследуется от Payment, но до сих пор платежные поведения.

Если вы хотите, чтобы получить Car методы экземпляра, вы могли бы сделать что-то вроде:

module Payments 
    module PaymentClassMethods 
    def some_class_method 
    end 
    def some_other_class_method 
    end 
    end 
    module PaymentInstanceMethods 
    def some_instance_method 
    end 
    def some_other_instance_method 
    end 
    end 
end 

module Payments 
    class Car 
    include PaymentInstanceMethods 
    extend PaymentClassMethods 
    end 
end 

Если вы делаете это много, вы можете повторно открыть Car класс, чтобы вы могли просто скажем include PaymentMethods и получить как метод класса, так и экземпляр. Но это немного другая тема.

Кроме того, если вы включаете (или расширяете) методы, которые взаимодействуют с моделями, отличными от Car, то я предлагаю вам рассмотреть возможность создания объекта службы. ИМО, модели должны знать очень мало друг о друге. Если вы модель Car, она знала много о других моделях, тогда вы могли бы столкнуться с какой-то жесткой связью - что может быть проблемой, если вы начнете обезьяну с вашей модели Car. Опять же, тема для отдельного обсуждения. Но, надеюсь, эта мысль помогает.

+0

Есть еще несколько соображений для вас, но я направляюсь в церковь. Вернемся к вам позже. – jvillian

+0

Удивительный! Спасибо вам, это очень ценится. Я решил вызвать модуль «Платежи», поскольку он содержит только классы, которые унаследованы от Платежа. – fbelanger

+0

О, хватит, это круто! Я не знаю, что это вполне соответствует моей ситуации, но чтение заставило меня вспомнить десятки раз, когда это было бы идеально! Отличный ответ сэр! – fbelanger

0

Хорошо, так что, называя как модуль, так и класс, то же самое усложняет ситуацию.

module A 
    class B 
    end 

    class C < B 
    end 
end 

A::C.superclass 
=> A::B 

Но если мы называем класс такой же, как модуль:

module A 
    class A 
    end 

    class B < A 
    end 
end 

TypeError: superclass mismatch for class B 

Если кто-то сталкивался с этой-то вещи или имеет какие-либо замечания или предложения, не стесняйтесь поделиться!