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形參,

 

 

 

 

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