结合Spring实现策略模式
最近系统需要对不同维度的数据进行差异化计算,也就会使用不同算法。为了以后更加容易扩展,结合Spring框架及策略模式对实现架构做了系统设计。
1. 定义策略接口(Strategy):
import com.dmall.scfc.biz.dao.model.ScfcScoreField; import com.dmall.scfc.biz.dao.model.ScfcScoreFieldValue; import com.dmall.scfc.biz.dto.ScoreModelDimensionDTO; import java.util.List; /** * @author wangxuexing * @descrption 数据抽取策略 * @date 2019/12/4 */ public interface Strategy { /** * 是否匹配策略 * @param scoreField 基础字段 * @return */ boolean isMatch(ScfcScoreField scoreField); /** * 根据具体字段抽取数据 * @param dimensionRule * @return */ List<ScfcScoreFieldValue> extractData(ScoreModelDimensionDTO dimensionRule) throws Exception; }
2. 实现具体策略
import java.util.List; /** * @author wangxuexing * @descrption scf-score 基础维度表按模型设置日期聚合策略 * @date 2019/12/4 */ @Service public class BaseBySettingStrategy implements Strategy { @Autowired private ScfcScoreFieldValueService scoreFieldValueService; @Override public boolean isMatch(ScfcScoreField scoreField) { return ProcessFlagEnum.BASE_BY_SETTING.getCode() == scoreField.getProcessFlag(); } @Override public List<ScfcScoreFieldValue> extractData(ScoreModelDimensionDTO dimensionRule) throws Exception { return scoreFieldValueService.getBaseFieldValueByDimension(dimensionRule); } }
可以继续往后继续实现多个算法,这里就不一一列举。
3. Spring Boot启动时初始化各算法
import com.dmall.scfc.task.strategy.Strategy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author wangxuexing * @descrption 加载所有抽取策略 * @date 2019/12/4 */ @Configuration public class ExtractStrategyConfig { @Autowired private ApplicationContext applicationContext; @Bean public List<Strategy> pipelineProcessors() { Map<String, Strategy> beansOfType = applicationContext.getBeansOfType(Strategy.class); List<Strategy> strategies = new ArrayList<Strategy>(); for (Strategy processService : beansOfType.values()) { strategies.add(processService); } return strategies; } }
4. 基于业务场景对不同策略经行调用
import com.dmall.dispatcher.sdk.util.IBasicExecuteContext; /** * @author wangxuexing * @descrption 数据抽取服务 * @date 2019/12/4 */ public interface DataExtractService { /** * 根据具体字段抽取数据 */ void extractData(); }
/** * @author wangxuexing * @descrption 上下文调用各策略 * @date 2019/12/4 */ @Slf4j @Service public class DataExtractServiceImpl implements DataExtractService { @Autowired private List<Strategy> strategyList; /** * 根据具体字段抽取数据 */ @Override public void extractData() { //查询所有核心企业,所有维度公式及条件 List<ScoreModelDimensionDTO> scoreModelDimensionDTOS = scfcScoreModelDimensionService.getAllScoreModelDimensions(); scoreModelDimensionDTOS.forEach(item -> { //执行不同满足匹配条件的策略 strategyList.forEach(strategy -> { extractAndInsertDataByStrategy(strategy, item); }); }); } /** * 根据策略抽取数据并插入 */ @Async//多线程异步计算插入数据 private void extractAndInsertDataByStrategy(Strategy strategy, ScoreModelDimensionDTO dimensionRule){ try{ List<Long> fieldIds = scoreFields.stream() .filter(scoreField -> strategy.isMatch(scoreField)) .map(x->x.getId()) .collect(Collectors.toList()); if(CollectionUtils.isNotEmpty(fieldIds)) { dimensionRule.setScoreRuleIds(fieldIds); //根据策略抽取数据 List<ScfcScoreFieldValue> resultList = strategy.extractData(dimensionRule); if(CollectionUtils.isNotEmpty(resultList)) { //设置维度ID及抓取时间 scoreFieldValueService.insertScoreFieldValueBatch(resultList); } } } catch (Exception e) { log.error("根据策略"+strategy.getClass().getName()+"抽取数据失败", e); } } }
每天一点成长,欢迎指正!