2015-10-25 7 views
7

Я читал Sandi Metz's Практический объектно-ориентированный дизайн в Ruby и многие сайты, обсуждающие дизайн в Ruby. То, что мне было трудно понять, - это правильный способ внедрения инъекции зависимостей.Что такое хорошая практика для инъекций зависимостей в Ruby?

В интернете залиты сообщения в блоге, в которых объясняется, как работает инъекция зависимостей в том, что я думаю, очень частично.

Я понимаю, что это должно быть плохо:

class ThisClass 
    def initialize 
    @another_class = AnotherClass.new 
    end 
end 

Хотя это решение:

class ThisClass 
    def initialize(another_class) 
    @another_class = another_class 
    end 
end 

И что я мог бы послать AnotherClass.new так:

this_class = ThisClass.new(AnotherClass.new) 

Это подход, который Санди Мец рекомендует, по крайней мере. Я не понимаю, куда должна идти такая линия? Он должен идти куда-то и вообще в примерах этого, что показано, это строка, подобная той, которая помещена полностью вне любого класса, метода или модуля, как если бы я просто вводил все это вручную в IRB для целей тестирования.

This post (среди прочих) предлагает этот другой подход:

class ThisClass 
    def another_class 
    @another_class ||= AnotherClass.new 
    end 
end 

Jamis Buck бы такой же подход, как это:

class AnotherClass 
end 

class ThisClass 
    def another_class_factory(class_name = AnotherClass) 
    class_name.new 
    end 
end 

Однако эти два примера, как сохранить имя AnotherClass внутри ThisClass, который Санди Мец говорит, что это одна из главных вещей, которые мы пытаемся избежать.

Так какова наилучшая практика для этого? Должен ли я создать модуль «зависимости», заполненный методами, которые являются фабриками для объектов каждого класса в моем приложении?

ответ

3

Что-то, что мне было трудно понять, это правильный способ внедрения инъекции зависимостей.

Я думаю, что лучшим определением «правильной» реализации является то, что соответствует объектно-ориентированному дизайну SOLID principles. В этом случае в основном используется принцип инверсии зависимостей .

В связи с этим, это единственным представленным решением, что делает не нарушает DIP (1):

class ThisClass 
    def initialize(another_class) 
    @another_class = another_class 
    end 
end 

Во всех остальных случаях, ThisClass имеет жесткую зависимость от AnotherClass, и не может функционировать без этого. Кроме того, если мы хотим заменить AnotherClass на треть, нам необходимо изменить ThisClass, что является нарушением принципа открытого замыкания .

Конечно, в приведенном выше примере именование переменной параметра и экземпляра another_class не является идеальным, поскольку мы не можем теперь (и не должны знать), какой объект передан нам, если он отвечает на ожидаемый интерфейс.Это красота полиморфизма.

Рассмотрим следующий пример, взятый из этого ThoughtBot video on DIP:

class Copier 
    def initialize(reader, writer) 
    @reader = reader 
    @writer = writer 
    end 

    def copy 
    @writer.write(@reader.read_until_eof) 
    end 
end 

Здесь вы можете пройти любые reader и writer объекты, которые отвечают read_until_eof и write соответственно. Это дает вам полную свободу, чтобы составить свой бизнес-логику, используя различные пары чтения и записи реализаций, даже во время выполнения:

Copier.new(KeyboardReader.new, Printer.new) 
Copier.new(KeyboardReader.new, NetworkPrinter.new) 

Что подводит нас к следующему вопросу.


Он должен идти куда-то и вообще в примерах это то, что показано это линия, как, что, будучи помещены полностью вне любого класса, метода или модуля [...]

Ты прав. Хотя объектное мышление предполагает моделирование домена с хорошо изолированными, развязанными и составными объектами, вам все равно нужно будет определить, как эти объекты взаимодействуют, чтобы реализовать любую бизнес-логику. В конце концов, иметь составные объекты нехорошо, если мы не составим их.

Аналогия, которая часто делается здесь, должна думать о ваших объектах как актеров. Вы директор , и вам все равно нужно создать сценарий (2), чтобы актеры знали, как взаимодействовать друг с другом.

То есть вам необходимо ввести пункт ввода в ваше приложение. Место, где начинается сценарий . Это само по себе может быть объектом - обычно абстрактным. В приложении с командной строкой это может быть ваш классический класс Main, а в приложении Rails это может быть ваш контроллер.

Это может показаться странным на первый взгляд, потому что в центре объекта мышления на моделировании конкретных объектов домена, и многое из всех трудов по этой теме посвящена этой работе, но только помните актера-сценария метафора , и ты будешь в пути.


я настоятельно рекомендую вам подобрать книгу Object Thinking. Это отличная работа, объясняющая мышление объектно-ориентированного дизайна, без которого знание специфических особенностей реализации языка становится довольно бесполезным.


(1): Следует отметить, что некоторые сторонники считают хранение экземпляра другого класса в переменном экземпляре анти-паттерн, но в Ruby, это довольно идиоматическое.

(2): Я не уверен, является ли это происхождение термина сценарием в программировании вообще, но, возможно, какой-то историк может пролить свет на это.

+0

Хранение экземпляра другого класса в переменной экземпляра не является анти-шаблоном, это своего рода точка, ограничивающая ее конкретную реализацию анти-шаблоном. Объекты очень часто состоят из других объектов. –

+0

Я не являюсь источником идеи @DaveNewton, и я не думаю, что это хорошо.Я посмотрю, смогу ли я снова выкопать источник. :-) – Drenmi

+0

Есть ли у вас какие-либо конкретные предложения по лучшим местам (местам) для ознакомления с различными классами? Лучше ли им быть в одном модуле/классе? Хорошо ли иметь знания о классах в некоторых классах, но просто старайтесь максимально уменьшить его? Часто подразумевается, что никогда не следует создавать объекты внутри классов, которые должны их использовать, а в зависимости от какого-либо внешнего процесса/службы/фабрики, чтобы сделать их для вас. Неправильно ли иметь свободные строки кода вне классов? Спасибо за очень продуманный ответ, я все еще путаюсь по этому вопросу! –

Смежные вопросы