目录
三、方式二:ApplicationContext获取Bean
一、背景
在执行业务的时候,对于不同情况将有不同的算法逻辑进行运算。比如,从前端或表记录中传递了一个字段mode,当mode为1时,执行策略1,;当mode为2时,执行策略2。对于以上算法的选择,以下有两种处理方式:
1、使用if,else逻辑判断分支,当值mode值为1时,调用策略1;否则调用策略2。当策略比较少的情况下,使用if,else是合适的,但是,当后期开发中我们逐步添加更多的策略时,每次都需要往if,else分支上再新增一个elseif分支进行判断,十分麻烦,而且不利于拓展。
2、剔除if,else分支。将策略Bean存放到Map中,调用时根据mode取Bean。或者根据mode每次直接从Spring容器中获取Bean。
以上将围绕2的两个方案进行,感兴趣的小伙伴可以往下看看。
二、方式一:Map获取Bean
1、创建一个策略枚举类,主要的作用是用于索引策略
public enum StrategyModeEnum {
ONE(1,"策略一"),
TWO(2, "策略二");
private final Integer index;
private final String info;
StrategyModeEnum(Integer index, String info){
this.index = index;
this.info = info;
}
public Integer getIndex() {
return index;
}
public String getInfo() {
return info;
}
}
2、创建一个注解,作用主要是标注在策略类上,用于标识策略类的基础信息(index, info)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface StrategyMode {
StrategyModeEnum mode();
}
3、创建一个抽象类BaseStrategy,以及两个子类OneStrategy、TwoStrategy
public abstract class BaseStrategy {
public abstract void invoke();
}
@StrategyMode(mode = StrategyModeEnum.ONE)
@Component("oneStrategy")
public class OneStrategy extends BaseStrategy {
@Override
public void invoke() {
System.out.println("1、先吃早餐");
System.out.println("2、再刷牙");
System.out.println("3、然后上班");
}
}
@StrategyMode(mode = StrategyModeEnum.TWO)
@Component("twoStrategy")
public class TwoStrategy extends BaseStrategy {
@Override
public void invoke() {
System.out.println("1、先刷牙");
System.out.println("2、再吃早餐");
System.out.println("3、然后上班");
}
}
4、创建一个StrategyConfig类,主要的作用是将步骤三的两个Bean对象存放到Map中
public class StrategyConfig {
// 会将容器中的两个bean:oneStrategy、twoStrategy注入到List中
@Resource
private List<BaseStrategy> strategyList = new ArrayList<>();
// 存放策略bean:1 -> oneStrategy, 2-> twoStrategy
private final Map<Integer, BaseStrategy> strategyMap = new ConcurrentHashMap<>();
@PostConstruct
private void init(){
// 遍历BaseStrategy类型的所有bean对象
strategyList.forEach(strategy -> {
// 获取到标注在BaseStrategy具体子类上的@StrategyMode注解,也就是OneStrategy和TwoStrategy类上的注解@StrategyMode注解
StrategyMode annotation = AnnotationUtils.findAnnotation(strategy.getClass(), StrategyMode.class);
if(null != annotation){
// 将策略对应枚举类型中的index基础信息进行保存
strategyMap.put(annotation.mode().getIndex(), strategy);
}
});
}
public BaseStrategy getStrategy(Integer mode){
return strategyMap.get(mode);
}
}
5、创建一个TestService类,继承StrategyConfig类,即可根据mode得到具体的策略
@Service
public class TestService extends StrategyConfig {
public void doInvoke(Integer mode){
BaseStrategy strategy = getStrategy(mode);
if(null == strategy){
return;
}
strategy.invoke();
}
}
6、测试上述功能
@SpringBootTest
@RunWith(SpringRunner.class)
public class AutoTest {
@Resource
private TestService testService;
@Test
public void testInvoke(){
testService.doInvoke(1);
//testService.doInvoke(2);
}
}
经过测试,能够选择到具体的策略进行执行
三、方式二:ApplicationContext获取Bean
1、改造策略枚举类,主要的作用是用于索引策略(此处beanName需要与OneStrategy、TwoStrategy注册时name一致)
public enum StrategyModeEnum {
ONE(1,"oneStrategy"),
TWO(2, "twoStrategy");
private final Integer index;
private final String bean;
StrategyModeEnum(Integer index, String bean){
this.index = index;
this.bean = bean;
}
public Integer getIndex() {
return index;
}
public String getInfo() {
return bean;
}
public StrategyModeEnum find(Integer mode){
StrategyModeEnum[] values = StrategyModeEnum.values();
for(StrategyModeEnum strategyMode : values){
if(strategyMode.getIndex().equals(mode)){
return strategyMode;
}
}
return null;
}
}
2、创建一个抽象类BaseStrategy,以及两个子类OneStrategy、TwoStrategy,同上(移除@StrategyMode注解)
3、创建SpringContextUtil,从容器中获取bean;改造StrategyConfig类,根据mode模式返回策略bean
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtil.applicationContext = applicationContext;
}
public static <T> T getBean(String beanName, Class<T> clazz){
return applicationContext.getBean(beanName, clazz);
}
}
public class StrategyConfig {
public BaseStrategy getStrategy(Integer mode){
StrategyModeEnum strategyModeEnum = StrategyModeEnum.find(mode);
BaseStrategy strategy = ApplicationContextUtil.getBean(strategyModeEnum.getBean(), BaseStrategy.class);
return strategy;
}
}
4、创建一个TestService类,继承StrategyConfig类,即可根据mode得到具体的策略,同上
四、总结
以上就是两个根据mode获取bean进行执行的方式,以上的方式主要就是剔除if,else分支,新增策略时减少改动地方