【问题标题】:Strategy within Spring bootSpring Boot 中的策略
【发布时间】:2017-06-26 14:11:06
【问题描述】:

您好,我在 Spring Boot 应用程序中有一个策略模式。我所有的策略都有自动装配的构造函数。我是弹簧靴的新手。我不知道如何为策略类编写我的工厂,因为自动装配的构造函数已经注入了依赖项。感谢您在这方面获得的任何帮助。

注意:我省略了接口和基类,以免样本混乱。

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
      }
    }
}

【问题讨论】:

    标签: java spring design-patterns spring-boot dependency-injection


    【解决方案1】:

    让你的 StrategyFactory 成为另一个 Spring bean,并在工厂中注入所有策略:

    @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.
        }
    }
    

    我通常使用枚举而不是字符串来标识策略,并且我让每个策略返回它处理的枚举值,因此迭代可以像

    return strategies.stream().filter(strategy -> strategy.getType() == type).findAny().orElseThrow(
        () -> new IllegalStateException("No strategy found for type " + type));
    

    当然,您也可以将策略存储在构造函数内的 Map 中,以使查找 O(1)。

    【讨论】:

    • 如果策略-是Spring bean怎么办?如何将 List 注入 StrategyFactory。这个列表是在哪里创建的?
    【解决方案2】:

    之前的所有答案都使用了非常直接的 spring DI 用法。但是,也可以使用 ServiceLocatorFactoryBean 来创建工厂,而无需在工厂中指定任何 bean。 首先为你的工厂定义一个接口:

    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 注册为惰性并具有不同的范围。

    【讨论】:

      【解决方案3】:

      我建议您将 StrategyFactory 设为 bean,然后将 Map&lt;String, Strategy&gt; 注入其中。 Spring 用策略 bean 的名称作为键填充它,值将是策略本身。那么你需要做的就是在那个Map上调用get

      这是一个例子:

      @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
      

      【讨论】:

        【解决方案4】:
        @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
              }
            }
        }
        

        使用相同的方法自动装配所有策略

        【讨论】:

          【解决方案5】:

          StrategyFactory 是另一个 Bean,它包含 Strategy 的所有实现

          @Component
          public class StrategyFactory {
          
              private Map<StrategyName, Strategy> strategies;
             
              @Autowired
              public StrategyFactory(Set<Strategy> strategySet) {
                  createStrategy(strategySet);
              }
          
              public Strategy findStrategy(StrategyName strategyName) {
                  return strategies.get(strategyName);
              }
          
              private void createStrategy(Set<Strategy> strategySet) {
                  strategies = new HashMap<StrategyName, Strategy>();
                  strategySet.forEach( strategy -> strategies.put( strategy.getStrategyName(), strategy));
              }
          }
          

          Strategy 接口及其所有实现

          public interface Strategy {
                  void doStuff();
                  StrategyName getStrategyName();
              }
          
          @Component
           public class StrategyA  implements Strategy{
                  @Override
                  public void doStuff() {
              
                  }
              
                  @Override
                  public StrategyName getStrategyName() {
                      return StrategyName.StrategyA;
                  }
              }
          
          @Component
          public class StrategyB  implements Strategy{
              @Override
              public void doStuff() {
          
              }
          
              @Override
              public StrategyName getStrategyName() {
                  return StrategyName.StrategyB;
              }
          }
          
          @Component
          public class StrategyC  implements Strategy{
          
              @Override
              public void doStuff() {
          
              }
              @Override
              public StrategyName getStrategyName() {
                  return StrategyName.StrategyC;
              }
          }
          

          我们有所有策略名称的枚举

           public enum StrategyName {
                  StrategyA,
                  StrategyB,
                  StrategyC
              }
          

          你终于可以连线StrategyFactory

           @Autowired
           private StrategyFactory strategyFactory;
          

          并获得所需的策略

          strategyFactory.findStrategy(StrategyName.StrategyA);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-11-07
            • 2020-03-18
            • 2019-08-19
            • 2021-12-19
            • 2017-04-09
            • 2023-04-01
            • 2021-03-01
            • 2021-08-14
            相关资源
            最近更新 更多