Я читал шаблон Factory и наткнулся на статьи, в которых предлагается использовать шаблон Factory в сочетании с внедрением зависимостей для максимизации возможности повторного использования и тестирования. Хотя я не смог найти никаких конкретных примеров этого гибрида Factory-DI, я собираюсь попробовать и привести несколько примеров кода моей интерпретации . Однако мой вопрос действительно о том, как этот подход улучшает тестируемость.
Моя интерпретация:
Итак, у нас есть Widget
класс:
public class Widget {
// blah
}
И мы хотим включить WidgetFactory
для управления построением Widget
s:
public interface WidgetFactory {
public abstract static Widget getWidget();
}
public class StandardWidgetFactory implements WidgetFactory {
@Override
public final static Widget getWidget() {
// Creates normal Widgets
}
}
public class TestWidgetFactory implements WidgetFactory {
@Override
public final static Widget getWidget() {
// Creates test/mock Widgets for unit testing purposes
}
}
Хотя в этом примере используется Spring DI (это единственный API, с которым я сталкивался), на самом деле не имеет значения, говорим ли мы о Guice или какой-либо другой инфраструктуре IoC; Идея в том, что теперь мы собираемся внедрить правильную WidgetFactory
реализацию во время выполнения, чтобы зависеть от того, тестируем ли мы код или работаем нормально. Весной конфигурация bean-компонентов может выглядеть следующим образом:
<bean id="widget-factory" class="org.me.myproject.StandardWidgetFactory"/>
<bean id="test-widget-factory" class="org.me.myproject.TestWidgetFactory"/>
<bean id="injected-factory" ref="${valueWillBeStdOrTestDependingOnEnvProp}"/>
Затем в коде:
WidgetFactory wf = applicationContext.getBean("injected-factory");
Widget w = wf.getWidget();
Таким образом, переменная среды (уровня развертывания), возможно, определенная где-то в файле .properties , решает, будет ли Spring DI внедрять StandardWidgetFactory
или TestWidgetFactory
.
Правильно ли я делаю это?!? Кажется, что очень много инфраструктуры просто получают хорошую тестируемость для моего Widget
. Не то чтобы я был против этого, но мне кажется, что это слишком изощренно.
Мое зависание:
Причина, по которой я спрашиваю это , заключается в том, что у меня будут другие объекты в других пакетах, в которых есть методы, использующие Widget
объекты внутри них. Возможно что-то вроде:
public class Fizz {
public void doSomething() {
WidgetFactory wf = applicationContext.getBean("injected-factory");
Widget widget = wf.getWidget();
int foo = widget.calculatePremable(this.rippleFactor);
doSomethingElse(foo);
}
}
Без этой огромной, по-видимому, излишне сложной установки, я бы не смог внедрить «mock Widgets
» в мой модульный тест для Fizz::doSomething()
.
Так что я разорван: с одной стороны мне просто кажется, что я слишком много думаю - что я вполне могу делать (если моя интерпретация неверна ). С другой стороны, я не вижу чистого способа обойти это.
В качестве продолжения касательного вопроса это также вызывает еще одну мою огромную озабоченность: если моя интерпретация верна (или даже несколько верна), то означает ли это, что нам нужно Factories
для каждого объекта?!?
Звучит, как путь-переобучение ! Что за отсечка? Какая линия на песке разграничивает использование фабрики, а когда нет ?! Спасибо за любую помощь и извинения за подробный вопрос. Просто у меня кружится голова.