Например

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

С помощью Spring я могу спроектировать такой объект как боб и внедрить его везде, где мне нужно:

public class MyClass {

    @Autowired
    private MyHelper helper;

    public void someMethod(String someKey) {
        AnInterface i = helper.giveMeTheRightImplementation(someKey);
        i.doYourjob();
    }

}

Теперь, как я должен реализовать помощник? Давайте начнем с этого:

@Service
public class MyHelper {

    public AnInterface giveMeTheRightImplementation(String key) {
        if (key.equals("foo")) return new Foo();
        else if (key.equals("bar")) return new Bar();
        else ...
    }

}

Такое решение имеет несколько недостатков. Одним из худших является тот факт, что экземпляры, возвращаемые помощником, неизвестны контейнеру и поэтому не могут извлечь выгоду из внедрения зависимости. Другими словами, даже если я определюFoo класс как это:

@Service
public class Foo {

    @Autowired
    private VeryCoolService coolService;

    ...

}

... случаиFoo вернулсяMyHelper не будет иметьcoolService поле правильно инициализировано.

Чтобы избежать этого, часто предлагаемое решение - ввестикаждая возможная реализация внутри помощника:

@Service
public class MyHelper {

    @Autowired
    private Foo foo;

    @Autowired
    private Bar bar;

    ...

    public AnInterface giveMeTheRightImplementation(String key) {
        if (key.equals("foo")) return foo;
        else if (key.equals("bar")) return bar;
        else ...
    }

}

Но я не большой поклонник таких решений. Я нахожу более элегантным и ремонтопригодным что-то вроде этого:

@Service
public class MyHelper {

    @Autowired
    private ApplicationContext app;

    public AnInterface giveMeTheRightImplementation(String key) {
        return (AnInterface) app.getBean(key);
    }

}

Это основано на веснеApplicationContext.

Аналогичное решение заключается в использованииServiceLocatorFactoryBean учебный класс:

public interface MyHelper {

    AnInterface giveMeTheRightImplementation(String key);

}

// Somewhere else, in Java config

@Bean
ServiceLocatorFactoryBean myHelper() {
    ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
    bean.setServiceLocatorInterface(MyHelper.class);
    return bean;
}

Но так как я не эксперт по Spring, мне интересно, есть ли еще лучшие подходы

Ответы на вопрос(3)

Ваш ответ на вопрос