With 策略模式

 

业务场景

前端使用一个data属性接收数据,而Highchart中对于不同的图表类型,接收数据的数据格式是不同的。

柱状图类型需要的是

{
    xData:["苹果","香蕉","梨子","橘子"],
    yData:[12,3,4,5]
}

那么前端赋值将data.xData、data.yData赋值给对应属性

而饼图需要的数据格式是

{
    {
        name:"苹果",
        y:12
    },
    {
        name:"香蕉",
        y:3
    },
    {
        name:"梨子",
        y:4
    },
    {
        name:"橘子",
        y:5
    },
}

这些图表实例的数据都保存在一个数据库表中,从表中取出来的数据的字段属性都是一致的,仅通过一个图表类型进行区分不同的策略类,具体策略会将同样一份数据封装为不同的数据格式供前端使用

实现

(1)定义策略类父接口


public interface ChartStrategy {

    Object recordHandleToDisplay(List<ChartRecord> records);
}

(2)具体策略类

柱状图

@Component("singleBaseChartStrategy")
public class SingleBaseChartStrategyImpl implements ChartStrategy{

    @Autowired
    private PctSeriesService pctSeriesService;

    @Override
    public Object recordHandleToDisplay(List<ChartRecord> records) {
        Map<String,Object> dataMap = new HashMap<>(4);

        //x轴信息集合(封装x轴数据)
        List<String> categories = new ArrayList<>();

        //查询出来该图表下拥有的所有数据列信息
        PctSeries pctSeries = pctSeriesService.selectBySingleChartId(records.get(0).getChartId());

        //数据列里的数据
        List<Double> dataList = new ArrayList<>();

        //将ChartRecord集合中的x、y轴数据存入集合
        for (ChartRecord chartRecord:records) {
            categories.add(chartRecord.getXValue());
            dataList.add(chartRecord.getYValue());
        }

        //封装series数据
        List<Map<String,Object>> series = new ArrayList<>();
        Map<String,Object> map = new HashMap<>(4);
        map.put("name",pctSeries.getName());
        map.put("colorByPoint",true);
        map.put("data",dataList);
        series.add(map);

        dataMap.put("categories",categories);
        dataMap.put("series",series);
        return dataMap;
    }
}

这里是使用map进行数据封装,其实最好应该定义一个业务领域模型类来替代Map,可以避免硬编码。这个策略类里data属性是一个List<Double>格式

注意:该类使用@Component注解,以注入到IOC容器中

饼图

@Component("basePieChartStrategy")
public class BasePieChartStrategyImpl implements ChartStrategy{

    @Autowired
    private PctSeriesService pctSeriesService;

    @Override
    public Object recordHandleToDisplay(List<ChartRecord> records) {
        //指定哈希Map集合长度
        int hashMapLength = 2;

        //得到该饼图的数据列
        PctSeries pctSeries = pctSeriesService.selectBySingleChartId(records.get(0).getChartId());

        //定义数据列集合
        List<Map<String,Object>> seriesList = new ArrayList<>();

        //定义数据列集合中的对象
        Map<String, Object> seriesMap = new HashMap<>(hashMapLength);

        //定义数据值集合
        List<Map<String, Object>> data = new ArrayList<>();

        //循环遍历赋值
        for (int i = 0; i < records.size(); i++) {
            Map<String, Object> map = new HashMap<>(hashMapLength);
            map.put("name", records.get(i).getXValue());
            map.put("y", records.get(i).getYValue());
            data.add(map);
        }

        seriesMap.put("name", pctSeries.getName());
        seriesMap.put("data", data);
        seriesList.add(seriesMap);

        return seriesList;
    }
}

这里将数据分别存储到name、y属性中

(3)策略上下文

它维护所有具体策略类型,向外暴露一个访问的接口,然后决定使用哪一种策略类

@Service("chartStrategyContext")
public class ChartStrategyContext {

    private static final String NO_CHART_RECORDS = "未找到图表数据";

    private static final String NO_CHART_TYPE_ENUM = "未找到对应ChartTypeEnum实例";

    private static final String NO_CHART_STRATEGY = "未找到对应图表策略实例";


    /**
     * context维护所有策略实现对象集
     */
    private final Map<String, ChartStrategy> strategyMap = new ConcurrentHashMap<>();

    /**
     *
     *
     * @date 14:15 2020/4/7
     * @author 李文龙
     * @param strategyMap: 容器中所有实现了ChartStrategy接口的实现类对象都会注入到该形参中
     *            k=beanId,v=全限定类名-实现类对象
     * @return
     **/
    @Autowired
    public ChartStrategyContext(Map<String, ChartStrategy> strategyMap) {
        this.strategyMap.clear();
        strategyMap.forEach((k, v) -> this.strategyMap.put(k, v));
    }

    public Map<String, ChartStrategy> getStrategyMap() {
        return this.strategyMap;
    }


    /**
     * 根据不同的图表类型-typeEn值,去Context中获取对应的策略实例
     * 去对源数据-records进行处理
     *
     * @date 14:33 2020/4/7
     * @author 李文龙
     * @param typeEn: Chart.typeEn值。图表类型
     * @param records:图表源数据,来自数据库表:PCT_RECORD等表
     * @return Object:不同的图表需要不同格式数据
     **/
    public Object recordHandleToDisplay(Long typeEn, List<ChartRecord> records) {
        ChartTypeEnum chartTypeEnum = ChartTypeEnum.getById(typeEn);
        ChartStrategy strategy;
        if(CollectionUtil.isEmpty(records)){
            return NO_CHART_RECORDS;
        }
        if (chartTypeEnum == null) {
            return NO_CHART_TYPE_ENUM;
        }
        strategy = strategyMap.get(chartTypeEnum.getBeanId());
        if (strategy == null) {
            return NO_CHART_STRATEGY;
        }

        return strategy.recordHandleToDisplay(records);
    }

}

注意:所有的具体策略类都使用了@Component注解注入到IOC容器中,该上下文类也使用了@Service来将其注入到IOC中。而该类的构造器有一个strategyMap形参,

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章