Подтвердить что ты не робот

Цель Guice

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

public SomeBarFooerImplementation(Foo foo, Bar bar) {
    this.foo = foo;
    this.bar = bar;
}

public void fooThatBar() {
    foo.fooify(bar);
}

И где-то более высокий уровень, возможно, в моей main(), у меня есть:

public static void main(String[] args) {
    Foo foo = new SomeFooImplementation();
    Bar bar = new SomeBarImplementation();
    BarFooer barFooer = new SomeBarFooerImplementation(foo, bar);

    barFooer.fooThatBar();
}

Теперь у меня в основном есть преимущества инъекции зависимостей, правильно? Легкость тестирования и т.д.? Конечно, если вы хотите, вы можете легко изменить main(), чтобы получить имена классов реализации из конфигурации вместо hardcoding.

Как я понимаю, сделать то же самое в Guice, я бы сделал что-то вроде:

public SomeModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Foo.class).to(SomeFooImplementation.class);
        bind(Bar.class).to(SomeBarImplementation.class);
        bind(BarFooer.class).to(SomeBarFooerImplementation.class);
    }
}

@Inject
public SomeBarFooerImplementation(Foo foo, Bar, bar) {
    this.foo = foo;
    this.bar = bar;
}

public static void main(String[] args) {
    Injector injector = Guice.createInjector(new SomeModule());
    Foo foo = injector.getInstance(Foo.class);

    barFooer.fooThatBar();
}

Это так? Мне кажется, что это просто синтаксический сахар, а не особенно полезный синтаксический сахар. И если есть преимущество в том, чтобы разбить "новый XxxImplementation()" материал на отдельный модуль, а не делать это непосредственно в main(), что легко сделать без Guice в любом случае.

У меня такое ощущение, что я пропустил что-то очень основное. Не могли бы вы объяснить мне, как выгодно использовать Guice?

Спасибо заранее.

4b9b3361

Ответ 1

В реальной жизни и больших приложениях уровень компонентов не равен 2 (как в вашем примере). Это может быть 10 или более. Также требования и зависимости могут измениться по прихоти.

При выполнении "DI вручную" это означает, что вы должны вручную изменить все пути ко всем компонентам и их транзитивным зависимостям. Это может быть совсем немного работы.

С "реальным DI" (т.е. Guice, Spring, CDI) вы просто меняете один или два затронутых компонента и проводку (Module на Guice) и что это.

Также: представьте, что некоторые из ваших глубоко вложенных компонентов находятся на фабриках, которые должны быть вызваны другими компонентами. В Guice вы просто вводите Provider<Foo> и это. Когда вы делаете это вручную, вы должны перетаскивать зависимости фабрик и их экземпляров в вашем коде.

Это еще более неприятно.

Изменить. Чтобы прояснить последнюю точку: изображение у вас есть глубоко вложенная логика (10 или более уровней). Внизу ваша логика должна создать factory на основе некоторого значения, например. фактическая температура: если "теплый", тогда требуется Cooler, если "холодно", то a Heater. Оба имеют интерфейс TemperatureAdjustor. Для Cooler и Heater требуется много разных зависимостей, чтобы выполнить свою работу.

Поскольку тип экземпляра фактора нельзя создать в main и передать его туда, где он нужен. Таким образом, вы в конечном итоге передаете зависимости обоих заводов до места, где они необходимы. ( "много зависимостей" плюс "много зависимостей" "слишком много, чтобы оставаться в здравом уме" )

С помощью "реального DI", такого как Guice, вы можете использовать AssistedInject, чтобы избежать беспорядка зависимостей и дать только фактическое значение для бизнеса (здесь: температура) для factory и сделать. Проводка factory выполняется в модуле.

Ответ 2

Диск с ручной кодировкой - это реальный DI.

Когда вы рассматриваете сложность контейнера IOC, вам нужно глубже изучить, почему вы его используете. Я был анти-МОК в течение долгого времени, имея возможность проектировать и внедрять чистый, быстрый, аккуратный ручной DI-код. Но я смирился с идеей контейнеров, потому что они помогают стандартизировать реализацию и предоставляют более основанный на конфигах механизм для добавления новых решений в уравнение зависимости. И кто-то еще написал их для вас, поэтому вам не нужно тратить время на ручную кодировку.

Многие говорят, что использовать контейнеры в больших приложениях и ручной код в маленьких. Я говорю об обратном. Маленькие приложения не настолько ограничены производительностью. Пойдите для скорости выполнения использования упакованного контейнера. В больших приложениях, где вы будете тратить много времени на оптимизацию, подумайте о ручном кодировании вашего DI.

edit: но позвольте мне добавить, что контейнер IOC или ручной код всегда используют DI и код для интерфейса - независимо от того, насколько просты приложения, над которыми вы работаете. Создавайте отличный код даже в маленьких приложениях.