Как избежать использования injector.createInstance () повсюду при использовании guice? - PullRequest
13 голосов
/ 21 октября 2010

Есть кое-что, чего я просто не понимаю: согласно тому, что я прочитал, я должен использовать Injector только в своем классе начальной загрузки (в автономном приложении это, как правило, находится в главном ( )), как в примере ниже (взято из справочной документации):

public static void main(String[] args) {
    /*
     * Guice.createInjector() takes your Modules, and returns a new Injector
     * instance. Most applications will call this method exactly once, in their
     * main() method.
     */
    Injector injector = Guice.createInjector(new BillingModule());

    /*
     * Now that we've got the injector, we can build objects.
     */
    RealBillingService billingService = injector.getInstance(RealBillingService.class);
    ...
  }

Но что, если не все объекты, которые мне когда-либо понадобятся, могут быть созданы во время запуска? Может быть, я хочу ответить на некоторые взаимодействия с пользователем, когда приложение работает? Разве мне не нужно где-то хранить свой инжектор (например, в качестве статической переменной) и затем вызывать injector.getInstance (SomeInterface.class), когда мне нужно создать новый объект?

Конечно, распространение вызовов Injector.getInstance () повсюду кажется нежелательным.

Что я тут не так делаю?

Ответы [ 3 ]

13 голосов
/ 21 октября 2010

Да, вам в основном следует использовать Injector, чтобы создать экземпляр экземпляра для корневого объекта.Остальная часть приложения не должна касаться Guice-контейнера.Как вы заметили, вам все равно нужно создавать некоторые объекты, когда это необходимо.Для этого есть разные подходы, каждый из которых подходит для разных нужд.

Внедрение провайдера Провайдер - это интерфейс от Guice.Это позволяет вам запросить новый экземпляр объекта.Этот объект будет создан с использованием Guice.Например.

 class MyService{
     private Provider<Transaction> transactionProvider;
     public MainGui(Provider<Transaction> transactionProvider){
         this.transactionProvider = transactionProvider;
     }

     public void actionStarted(){
         Transaction transaction = transactionProvider.get();
     }

Построй фабрику Часто тебе нужна какая-то фабрика.Эта фабрика использует некоторые внедренные сервисы и некоторые параметры и создает новый объект для вас.Затем вы используете эту фабрику для новых экземпляров.Затем вы вводите эту фабрику и используете ее.Для этого также есть помощь с AssistedInject -extension

Я думаю, что с этими двумя возможностями вам редко нужно использовать сам Guice-Injector.Однако иногда все же целесообразно использовать сам инжектор.Затем вы можете ввести инжектор в компонент.

3 голосов
/ 22 октября 2010

Чтобы расширить ответ, опубликованный Gamlor, вам также необходимо различать типы объектов, которые вы используете.

Для сервисов внедрение является правильным решением, однако, не пытайтесь всегда делать объекты данных (которые обычно являются листами в вашем графе объектов) инъекционными. Могут быть ситуации, когда это правильное решение, но введение Provider<List>, вероятно, не очень хорошая идея. Мой коллега закончил тем, что сделал это, это сделало кодовую базу очень запутанной через некоторое время. Мы только что закончили все это очищать, и модули Guice теперь стали более конкретными.

0 голосов
/ 25 октября 2010

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

BillingService billingService = injector.getInstance(BillingService.class);
billingService.respondToUserEvent( event );

Я думаю, что это может быть немногоабстрактно, но основная идея в том, что вы получаете от Guice свой класс приложений верхнего уровня.Судя по вашему вопросу, я думаю, что BillingService - это не ваш класс высшего уровня?

...