Лучший способ ввести класс, экземпляром которого нельзя управлять? - PullRequest
1 голос
/ 16 марта 2011

Я довольно новичок в Guice, так что, надеюсь, это не очевидный вопрос ...

Я имею дело со структурой, которая динамически создает один из моих классов приложений (назовем его C) используя отражение, поэтому я не имею никакого контроля над его созданием.Более того, у меня нет простого способа получить доступ к вновь созданному C после того, как фреймворк его мгновенно запустил.Вот как выглядит C:

    public class C implements I {

        public C() {
            // this ctor is invoked by the framework so can't use DI here?
        }        

        public void initialize() {
            // this is a post instantiation hook which the f/w will invoke
        }

        private void m() {
            Dependency d = Dependency.getInstance();
            d.doSmth();
        }
    }

Я бы хотел, чтобы C получил Dependency, используя DI.Здесь Dependency явно одноэлементный, но в общем случае это не обязательно.

Я предложил два возможных решения, ни одно из которых не выглядит очень опрятным, поэтому я решил спросить экспертов:

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

  2. Каркас поддерживаетхук для C, чтобы инициализировать себя после создания (метод initialize(), показанный выше).Этот метод может самостоятельно внедрить вновь созданный экземпляр, используя установку сеттера.

С 2, я думаю, это означает большую внешнюю изменяемость, но, по крайней мере, демонстрирует зависимость немного более явно для таких вещей, как unitтесты.Проблема в том, как мне в этом случае достать Guice Injector (если не полагаться на еще один сервисный локатор)?Я также прочитал (и склонен согласиться с этим), что явная ссылка на Инжектор в коде приложения - сомнительная практика.

Ваше понимание будет действительно оценено.

Большое спасибо,
Christian

Ответы [ 2 ]

2 голосов
/ 17 марта 2011

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

public class C implements I {
  @Inject static Provider<Dep1> dep1Provider;
  @Inject static Provider<Dep2> dep2Provider;

  ...

  public void initialize() {
    Dep1 dep1 = dep1Provider.get();
    Dep2 dep2 = dep2Provider.get();
    ...
  }
}
1 голос
/ 20 марта 2011

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

public class C implements I {

    public C() {
        // this ctor is invoked by the framework, you can't do injection here.
    }        

    public void initialize() {
        MyGuice.getInjector().inject(this);
    }

    @Inject
    protected void init(Dep1 dep1, Dep2 dep2) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    private void m() {
        dept1.doSmth();
    }
}

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

@Configurable
public class C implements I {

    public C() {
        // this ctor is invoked by the framework, you can't do injection here.
    }        

    @Inject
    protected void init(Dep1 dep1, Dep2 dep2) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    private void m() {
        dept1.doSmth();
    }
}
...