Стратегия в рамках Spring boot
Привет у меня есть шаблон стратегии в приложении spring boot. Во всех моих стратегиях есть автоматические конструкторы. Я новичок в spring boot. У меня нет простейшей идеи, как я собираюсь написать свою фабрику для классов стратегий, поскольку autowired конструкторы ввели зависимости. Я ценю любую помощь с этим.
Примечание: я оставляю Intefaces и базовые классы, чтобы не загромождать образец.
public class StrategyA implement Strategy {
private DependencyA depA;
private DependencyB depB;
@Autowired
public StragegyA(DependencyA depA, DependencyB depB) {
this.depA = depA;
this.depB = depB;
}
}
public class StrategyB implements Strategy {
private DependencyA depA;
private DependencyB depB;
@Autowired
public StragegyB(DependencyA depA, DependencyB depB) {
this.depA = depA;
this.depB = depB;
}
}
public class StrategyFactory {
public Strategy getStrategy(String strategyName) {
if (name.equals("StrategyA")) {
<b>return StrategyA; //My problem is here
} else {
return StrategyB; // And Here
}
}
}
4 ответов
все предыдущие ответы используют довольно прямое использование spring DI. Однако также можно использовать ServiceLocatorFactoryBean для создания фабрики без указания какого-либо компонента на фабрике. Сначала определите интерфейс для вашей фабрики:
public interface MyFactory {
Strategy get(String type);
}
// Could be an abstract class
public interface Strategy {
void doStuff();
}
затем приложения:
@Configuration
public class AppConfiguration {
@Autowired
private BeanFactory beanFactory;
public ServiceLocatorFactoryBean myFactoryLocator() {
final ServiceLocatorFactoryBean locator = new ServiceLocatorFactoryBean();
locator.setServiceLocatorInterface(MyFactory.class);
locator.setBeanFactory(beanFactory);
return locator;
}
@Bean
public MyFactory myFactory() {
final ServiceLocatorFactoryBean locator = myFactoryLocator();
locator.afterPropertiesSet();
return (MyFactory) locator.getObject();
}
}
Теперь вы можете определить bean (используя аннотацию @Service, @Component или @Bean), который реализует / расширяет, и они автоматически регистрируются в MyFactory Bean и может быть создан с:
myFactory.get("beanName");
лучшая часть заключается в том, что вы можете зарегистрировать Strategy bean как ленивый и с разными областями.
Сделайте ваш StrategyFactory другой фасоль Весны, и впрысните все стратегии в Фабрике:
@Component
public class StrategyFactory {
private final List<Strategy> strategies;
@Autowired
public StrategyFactory(List<Strategy> strategies) {
this.strategies = strategies;
}
public Strategy getStrategy(String strategyName) {
// iterate through the strategies to find the right one, and return it.
}
}
Я обычно использую перечисление, а не строку для идентификации stratehy, и я заставляю каждую стратегию возвращать значение перечисления, которое она обрабатывает, поэтому итерация может быть такой же простой, как
return strategies.stream().filter(strategy -> strategy.getType() == type).findAny().orElseThrow(
() -> new IllegalStateException("No strategy found for type " + type));
конечно, вы также можете сохранить стратегии в карте внутри конструктора, чтобы сделать поиск O(1).
Я бы предложил вам сделать ваш StrategyFactory
Боб и ввести в него Map<String, Strategy>
. Весна заполнить его с именем стратегии bean в качестве ключа и значение будет сама стратегия. Тогда все что вам нужно сделать, это позвонить get
на Map
.
вот пример:
@SpringBootApplication
public class So44761709Application {
public static void main(String[] args) {
SpringApplication.run(So44761709Application.class, args);
}
public interface Strategy { }
@Component
public static class DependencyA {}
@Component
public static class DependencyB {}
@Component("StrategyA")
public static class StrategyA implements Strategy {
private DependencyA depA;
private DependencyB depB;
@Autowired
public StrategyA(DependencyA depA, DependencyB depB) {
this.depA = depA;
this.depB = depB;
}
}
@Component("StrategyB")
public class StrategyB implements Strategy {
private DependencyA depA;
private DependencyB depB;
@Autowired
public StrategyB(DependencyA depA, DependencyB depB) {
this.depA = depA;
this.depB = depB;
}
}
@Component
public class StrategyFactory {
@Autowired
private Map<String, Strategy> strategies;
public Strategy getStrategy(String strategyName) {
return strategies.get(strategyName);
}
}
@Bean
CommandLineRunner run(StrategyFactory strategyFactory) {
return args -> {
System.out.println(strategyFactory.getStrategy("StrategyB").getClass().getSimpleName());
System.out.println(strategyFactory.getStrategy("StrategyA").getClass().getSimpleName());
};
}
}
принты:
StrategyB
StrategyA
@Component
public class StrategyFactory {
private StrategyA sA;
private StrategyB sB;
@Autowired
public StrategyFactory (StrategyA sA, StrategyB sB) {
this.sA = sA;
this.sB = sB;
}
public Strategy getStrategy(String strategyName) {
if (name.equals("StrategyA")) {
return sA; //My problem is here
} else {
return sB; // And Here
}
}
}
используйте тот же подход с autowiring все стратегии