Spring Boot中的策略

8

你好,我在一个Spring Boot应用程序中使用了策略模式。我的所有策略都有自动装配构造函数。我是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
      }
    }
}
5个回答

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

让您的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)。

如果Strategy是Spring Bean,该怎么办?我如何将List <Strategy> 注入到StrategyFactory中?这个List是在哪里创建的? - ip696

5
所有之前的答案都使用了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();
    }
}

现在您可以定义一个使用注释@Service、@Component或@Bean的bean,它们会自动注册到MyFactory bean中,并且可以使用以下方式创建:

myFactory.get("beanName");

最好的部分是您可以将策略bean注册为延迟加载且具有不同的作用域。

3
我建议你把你的StrategyFactory设置为一个bean并注入一个Map<String, Strategy>。Spring会把策略bean的名称作为键填充到Map中,而值则是策略本身。这样,你只需要在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

3

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);

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接