最近系統需要對不同維度的數據進行差異化計算,也就會使用不同算法。為了以后更加容易擴展,結合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); } } }