JAVA策略组合模式

背景:策略模式+工厂+自定义注解+Spring管理。 应用于多种多策略业务场景下,无需关注创建策略对象和调用逻辑。

1.自定义策略注解,value为匹配的具体策略,order执行顺序。
/**
 *  策略上使用@Strategy标记来实现扫描功能
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IStrategy {
    String value();
    int order() default 9999999;
}
2.扫描注解,注入具体策略到spring容器。
@Slf4j
public class StrategyBootstrap implements ImportBeanDefinitionRegistrar {

    private BeanDefinitionRegistry registry;

    /**
     * 反射具体策略类,注入到Spring容器
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        getBeanDefinition().forEach(it -> {
            Class<?> aClass = null;
            try {
                aClass = Class.forName(it.getBeanClassName());
            } catch (ClassNotFoundException e) {
                log.error("Class.forName失败",e);
            }
            IStrategy annotation = aClass.getAnnotation(IStrategy.class);
            registry.registerBeanDefinition(annotation.value(), it);
        });
    }

    /**
     * 通过注解获扫描出所有的策略类,并且生成spring的beanDefinition
     */
    protected static Set<BeanDefinition> getBeanDefinition(){
        Set<BeanDefinition> beanDefinitionSets = new HashSet<>();
        ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AnnotationTypeFilter(IStrategy.class));
        Set<String> scanBasePackages = MySoftManifestProvider.getEntityResources();
        for (String scanBasePackage : scanBasePackages) {
            Set<BeanDefinition> beanDefinitionSet = provider.findCandidateComponents(scanBasePackage);
            beanDefinitionSet.forEach(it -> beanDefinitionSets.addAll(beanDefinitionSet));
        }
        return beanDefinitionSets;
    }
}
3.申明策略工厂,隐藏创建策略细节
/**提供StrategyFactory来缓存注册信息,并获取实例执行*/
public interface StrategyFactory<T> {
    /**手动注册策略*/
    void register(Class<T> strategyClass);
    /**获取策略*/
    T getStrategy(String name);
    /**获取策略名称列表*/
    List<String> getStrategies(Class<T> tClass);
}
@Slf4j
public class StrategyFactoryService<T> implements StrategyFactory<T>, ImportBeanDefinitionRegistrar {

    private BeanDefinitionRegistry registry;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        this.registry = registry;
    }

    /**
     * 通过注解value, 获取单个策略对象
     */
    @Override
    public T getStrategy(String name) {
        T strategyInstance = (T) SpringContextHolder.getBean(name);
        if (strategyInstance == null) throw new IllegalArgumentException("没有对应的类型");
        return strategyInstance;
    }

    /**
     * 通过基类获取对应的所有策略注解value
     */
    @Override
    public List<String> getStrategies(Class<T> tClass) {
        @Getter
        @Setter
        @AllArgsConstructor
        class Strategies { int sort;String value;}
        List<Strategies> strategies = new ArrayList<>();
        for (BeanDefinition beanDefinition : StrategyBootstrap.getBeanDefinition()) {
            Class<?> aClass = null;
            try {
                aClass = Class.forName(beanDefinition.getBeanClassName());
            } catch (ClassNotFoundException e) {
                log.error("Class.forName失败",e);
            }
            if(aClass.getSuperclass().equals(tClass) || Arrays.stream(aClass.getInterfaces()).filter(it -> it.equals(tClass)).collect(Collectors.toList()).size() > 0) {
                IStrategy annotation = aClass.getAnnotation(IStrategy.class);
                strategies.add(new Strategies(annotation.order(), annotation.value()));
            }
        }
        return strategies.stream().sorted(Comparator.comparing(Strategies::getSort)).map(it -> it.getValue()).collect(Collectors.toList());
    }

   /**
     * 手动将策略注册到spring容器
     */
    @Override
    public void register(Class<T> strategyClass) {
        String name = strategyClass.getAnnotation(IStrategy.class).value();
        registry.registerBeanDefinition(name, BeanDefinitionBuilder.genericBeanDefinition(strategyClass).getBeanDefinition());
    }

}
4.使用示例。(以我最近编写的Excel导入为例)
1.申明Excel执行流程策略接口
/**流程扩展*/
public interface StrategyProcess {
    void process(ImportContext importContext);
}
2.实现Excel导入流程
@Slf4j
@IStrategy(value = "验证数据", order =1)
public class StrategyDataValidation implements StrategyProcess {
    @Override
    public void process(ImportContext importContext) {
          //数据验证逻辑
    }
}
@Slf4j
@IStrategy(value = "导入数据", order = 2)
public class StrategyDataInit implements StrategyProcess {
        @Override
    public void process(ImportContext importContext) {
                //数据导入逻辑
        }
}
3.执行代码
@Autowired
private StrategyFactory<StrategyProcess> strategyFactory;
	 //getStrategies: 获取导入流程接口的所有策略,返回策略对应的执行value
	 List<String> strategies = strategyFactory.getStrategies(StrategyProcess.class);
	 //遍历执行导入流程策略
	 strategies.forEach(it -> {
	 	  //getStrategy: 根据策略执行的value获取具体的执行对象,比如:StrategyDataInit,StrategyDataValidation
	      StrategyProcess strategy = strategyFactory.getStrategy(it);
	      //process: 执行策略
	      strategy.process(importContext);
	 });
4.执行结果

数据初始化逻辑。。。。。
数据验证逻辑。。。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值