结合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);
        }
    }
}
原文地址:https://www.cnblogs.com/barrywxx/p/12003517.html