Стратегия в рамках 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 все стратегии