0


策略模式-类型统计

文章目录


前言

在做统计的业务开发中,常常伴随着用户选择不同类型的统计而动态的加载数据,返回的数据也会动态的改变,比如说一张商超里面可能有贩卖肉蛋禽、蔬菜、饮料、水果等,我们需要根据这几种类型指标(算法不同)去生成各自的统计数据,如果根据不同的类型写不同的接口,可以实简单现该功能,但带来的问题是接口定义太多,重复方法定义过多,如果统一一个接口、内容使用if去走分支,也可以实现相同的效果,但还是不够理想化,理想的是不需要手动的添加if分支,而是做到自动匹配到对应算法执行指定的流程,那么这时候就需要策略模式来帮我们实现这一步操作了

一、策略模式是什么?

  • 策略模式是一种行为型设计模式,它定义了一系列算法或策略,并将它们封装起来,使它们可以互相替换。在使用策略模式时,可以通过改变不同的算法或策略来改变对象的行为。
  • 策略模式通常包含两部分:策略接口和策略实现类。策略接口定义了对某种行为的抽象,而策略实现类则提供了具体的算法或策略实现。

二、策略模式应用场景

  1. 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。
  2. 需要动态选择算法和策略时。
  3. 当一个对象需要通过多种行为方式中的一种进行某种操作时。
  4. 在不希望客户端知道具体实现细节的情况下,可采用策略模式对外提供接口。
  5. 多个类只有在算法或行为上稍有不同的场景。
  6. 假设有一个系统需要根据用户的不同操作系统显示不同的界面风格。可以使用策略模式,将不同操作系统的界面风格作为不同的策略实现类,并通过定义一个策略接口来对外暴露相应的方法。
  7. 策略模式还可以用于设计游戏中的战斗系统,根据不同角色的属性和职业特点,选取最优的战斗策略进行战斗。 总之,策略模式适用于多个类只有在算法或行为上稍有不同的场景,并且在运行时需要动态地选择不同的算法或策略的情况下。

三、策略模式优点

  1. 策略模式可以让算法或策略独立于使用它们的客户端而变化,从而实现代码复用。
  2. 策略模式可以让算法或策略在不影响代码结构的情况下灵活地变化,降低了代码维护的成本。
  3. 策略模式可以避免使用大量的 if-else 语句或者 switch 语句来进行分支处理,增强了代码的可读性和可维护性。
  4. 策略模式可以在运行时动态地改变算法或策略,因此可以根据需要进行适当的选择和组合。

四、策略模式缺点

  1. 策略模式会增加系统需要的类的数量,可能会导致代码变得更加复杂和难以理解。
  2. 策略模式需要客户端了解不同的策略之间的差异,增加了客户端的编码难度。
  3. 策略模式可能会导致不必要的运行时开销,因为需要动态地选择和组合算法或策略。

五、场景案例:类型统计

1.项目结构

在这里插入图片描述


2.UML图解

在这里插入图片描述


3.代码实现

3.1 指标枚举

importcom.fasterxml.jackson.annotation.JsonFormat;importlombok.AllArgsConstructor;importlombok.Getter;@Getter@AllArgsConstructor@JsonFormat(shape =JsonFormat.Shape.OBJECT)publicenumStatisticalIndicatorsEnum{/**
     * 肉
     */MEAT(1,"肉","meatAnalysisTableService"),/**
     * 水果
     */FRUIT(2,"水果","fruitAnalysisTableService"),/**
     * 蔬菜
     */VEGETABLE(3,"蔬菜","vegetableAnalysisTableService"),/**
     * 饮料
     */BEVERAGE(4,"饮料","beverageAnalysisTableService");/**
     * 编码
     */privatefinalInteger code;/**
     * 注释
     */privatefinalString desc;/**
     * 对应策略
     */privatefinalString strategyName;}

3.2 请求体

importcom.fasterxml.jackson.annotation.JsonFormat;importcom.mxf.code.strategy_factory.enums.StatisticalIndicatorsEnum;importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importorg.springframework.web.bind.annotation.ModelAttribute;importjavax.validation.constraints.NotBlank;importjavax.validation.constraints.NotNull;importjava.io.Serializable;importjava.util.Date;/**
 * 统计图Request
 */@Data@ApiModel(value ="统计图Request")publicclassStatisticsRequestimplementsSerializable{privatestaticfinallong serialVersionUID =1L;@NotBlank(message ="统计指标不能为空")@ApiModelProperty(value ="统计指标")privateStatisticalIndicatorsEnum statisticalIndicatorsEnum;@NotNull(message ="统计起始时间不能为空")@ApiModelProperty(value ="开始时间,格式:yyyy-MM-dd")@JsonFormat(pattern ="yyyy-MM-dd")privateDate startDate;@NotNull(message ="统计截止时间不能为空")@ApiModelProperty(value ="结束时间(格式:yyyy-MM-dd)")@JsonFormat(pattern ="yyyy-MM-dd")privateDate endDate;@ModelAttribute("statisticalIndicators")publicvoidsetStatisticalIndicatorsEnum(StatisticalIndicatorsEnum statisticalIndicatorsEnum){this.statisticalIndicatorsEnum = statisticalIndicatorsEnum;}}

3.3 响应体

importlombok.Data;/**
 * @author mxf
 * @version 1.0
 * @description: 响应体Base
 * @date 2023/5/26
 */@DatapublicabstractclassBaseResponse{}
importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importlombok.EqualsAndHashCode;importjava.io.Serializable;importjava.math.BigDecimal;/**
 * @author 28382
 */@Data@ApiModel(value ="蔬菜")@EqualsAndHashCode(callSuper =true)publicclassBeverageAvailabilityListResponseextendsBaseResponseimplementsSerializable{privatestaticfinallong serialVersionUID =1L;@ApiModelProperty(value ="统计时间")privateString xDate;@ApiModelProperty(value ="饮料类型名称")privateString beverageTypeName;@ApiModelProperty(value ="销售件数")privateDouble salesQuantity;@ApiModelProperty(value ="销售金额")privateBigDecimal salesAmount;}
importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importlombok.EqualsAndHashCode;importjava.io.Serializable;importjava.math.BigDecimal;/**
 * @author 28382
 */@Data@ApiModel(value ="水果图表响应体")@EqualsAndHashCode(callSuper =true)publicclassFruitAvailabilityChartResponseextendsBaseResponseimplementsSerializable{privatestaticfinallong serialVersionUID =1L;@ApiModelProperty(value ="统计时间")privateString xDate;@ApiModelProperty(value ="本年销售总额")privateBigDecimal currentYearSalesAmount;@ApiModelProperty(value ="去年销售金额")privateBigDecimal previousYearSalesAmount;}
importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importlombok.EqualsAndHashCode;importjava.io.Serializable;importjava.math.BigDecimal;/**
 * @author 28382
 */@Data@ApiModel(value ="水果")@EqualsAndHashCode(callSuper =true)publicclassFruitAvailabilityListResponseextendsBaseResponseimplementsSerializable{privatestaticfinallong serialVersionUID =1L;@ApiModelProperty(value ="统计时间")privateString xDate;@ApiModelProperty(value ="肉类名")privateString fruitTypeName;@ApiModelProperty(value ="销售量kg")privateDouble salesVolume;@ApiModelProperty(value ="销售金额")privateBigDecimal salesAmount;}
importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importlombok.EqualsAndHashCode;importjava.io.Serializable;importjava.math.BigDecimal;/**
 * @author 28382
 */@Data@ApiModel(value ="肉")@EqualsAndHashCode(callSuper =true)publicclassMeatAvailabilityListResponseextendsBaseResponseimplementsSerializable{privatestaticfinallong serialVersionUID =1L;@ApiModelProperty(value ="统计时间")privateString xDate;@ApiModelProperty(value ="肉类名")privateString meatTypeName;@ApiModelProperty(value ="销售量kg")privateDouble salesVolume;@ApiModelProperty(value ="销售金额")privateBigDecimal salesAmount;}
importio.swagger.annotations.ApiModel;importio.swagger.annotations.ApiModelProperty;importlombok.Data;importlombok.EqualsAndHashCode;importjava.io.Serializable;importjava.math.BigDecimal;/**
 * @author 28382
 */@Data@ApiModel(value ="蔬菜")@EqualsAndHashCode(callSuper =true)publicclassVegetableAvailabilityListResponseextendsBaseResponseimplementsSerializable{privatestaticfinallong serialVersionUID =1L;@ApiModelProperty(value ="统计时间")privateString xDate;@ApiModelProperty(value ="肉类名")privateString vegetableName;@ApiModelProperty(value ="销售量kg")privateDouble salesVolume;@ApiModelProperty(value ="销售金额")privateBigDecimal salesAmount;}

3.4.分析统计指标策略

管理策略bean
importcom.mxf.code.strategy_factory.enums.StatisticalIndicatorsEnum;importorg.springframework.stereotype.Service;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;/**
 * 分析统计指标策略
 *
 * @author 28382
 */@ServicepublicclassAnalysisTableStrategyContext{privatefinalMap<String,AnalysisTableService> analysisTableMap =newConcurrentHashMap<>();publicAnalysisTableStrategyContext(Map<String,AnalysisTableService> strategyMap){this.analysisTableMap.putAll(strategyMap);}/**
     * @param statisticalIndicatorsEnum 指标枚举
     * @return com.mxf.code.strategy_factory.service.AnalysisTableService
     * @author mxf
     * @description 获取实际统计策略
     * @createTime 2023/5/26 14:08
     * @paramType [com.mxf.code.strategy_factory.enums.StatisticalIndicatorsEnum]
     */publicAnalysisTableServicegetResource(StatisticalIndicatorsEnum statisticalIndicatorsEnum){return analysisTableMap.get(statisticalIndicatorsEnum.getStrategyName());}}

3.5.接口

importcom.mxf.code.strategy_factory.request.StatisticsRequest;importcom.mxf.code.strategy_factory.response.BaseResponse;importjava.util.List;/**
 * 统计分析
 */publicinterfaceAnalysisTableService{/**
     * 获取统计图数据
     *
     * @param requestParams 入参
     * @return
     */List<BaseResponse>getChartData(StatisticsRequest statisticsRequest);/**
     * 获取列表数据
     *
     * @param requestParams 入参
     * @return
     */List<BaseResponse>getListData(StatisticsRequest statisticsRequest);}

3.6.扩展接口

importcom.mxf.code.strategy_factory.request.StatisticsRequest;/**
 * @author mxf
 * @version 1.0
 * @description: 水果(自定义接口)
 * @date 2023/5/26
 */publicinterfaceFruitAnalysisTableService{/**
     * 获取水果库存
     *
     * @param statisticsRequest 入参
     * @return
     */DoublegetObtainInventory(StatisticsRequest statisticsRequest);}

3.7.接口实现

importcom.mxf.code.strategy_factory.request.StatisticsRequest;importcom.mxf.code.strategy_factory.response.BaseResponse;importcom.mxf.code.strategy_factory.response.BeverageAvailabilityListResponse;importcom.mxf.code.strategy_factory.service.AnalysisTableService;importorg.springframework.stereotype.Service;importjava.math.BigDecimal;importjava.util.ArrayList;importjava.util.List;/**
 * @author mxf
 * @version 1.0
 * @description: 饮料
 * @date 2023/5/26
 */@Service("beverageAnalysisTableService")publicclassBeverageAnalysisTableServiceImplimplementsAnalysisTableService{@OverridepublicList<BaseResponse>getChartData(StatisticsRequest requestParams){returnnull;}@OverridepublicList<BaseResponse>getListData(StatisticsRequest statisticsRequest){List<BeverageAvailabilityListResponse> resultList =newArrayList<>();BeverageAvailabilityListResponse beverageAvailabilityListResponse =newBeverageAvailabilityListResponse();
        beverageAvailabilityListResponse.setXDate("");
        beverageAvailabilityListResponse.setBeverageTypeName("");
        beverageAvailabilityListResponse.setSalesQuantity(0.0D);
        beverageAvailabilityListResponse.setSalesAmount(newBigDecimal("0"));
        resultList.add(beverageAvailabilityListResponse);returnnewArrayList<>(resultList);}}
importcom.mxf.code.strategy_factory.request.StatisticsRequest;importcom.mxf.code.strategy_factory.response.BaseResponse;importcom.mxf.code.strategy_factory.response.FruitAvailabilityChartResponse;importcom.mxf.code.strategy_factory.response.FruitAvailabilityListResponse;importcom.mxf.code.strategy_factory.service.AnalysisTableService;importcom.mxf.code.strategy_factory.service.FruitAnalysisTableService;importorg.springframework.stereotype.Service;importjava.math.BigDecimal;importjava.util.ArrayList;importjava.util.List;/**
 * @author mxf
 * @version 1.0
 * @description: 水果
 * @date 2023/5/26
 */@Service("fruitAnalysisTableService")publicclassFruitAnalysisTableServiceImplimplementsAnalysisTableService,FruitAnalysisTableService{@OverridepublicList<BaseResponse>getChartData(StatisticsRequest requestParams){List<FruitAvailabilityChartResponse> resultList =newArrayList<>();FruitAvailabilityChartResponse fruitAvailabilityChartResponse =newFruitAvailabilityChartResponse();
        fruitAvailabilityChartResponse.setXDate("2022-05-25");
        fruitAvailabilityChartResponse.setCurrentYearSalesAmount(newBigDecimal("4"));
        fruitAvailabilityChartResponse.setPreviousYearSalesAmount(newBigDecimal("5"));FruitAvailabilityChartResponse fruitAvailabilityChartResponse2 =newFruitAvailabilityChartResponse();
        fruitAvailabilityChartResponse2.setXDate("2022-05-26");
        fruitAvailabilityChartResponse2.setCurrentYearSalesAmount(newBigDecimal("1"));
        fruitAvailabilityChartResponse2.setPreviousYearSalesAmount(newBigDecimal("2"));
        resultList.add(fruitAvailabilityChartResponse);
        resultList.add(fruitAvailabilityChartResponse2);returnnewArrayList<>(resultList);}@OverridepublicList<BaseResponse>getListData(StatisticsRequest statisticsRequest){List<FruitAvailabilityListResponse> resultList =newArrayList<>();FruitAvailabilityListResponse fruitAvailabilityListResponse =newFruitAvailabilityListResponse();
        fruitAvailabilityListResponse.setXDate("");
        fruitAvailabilityListResponse.setFruitTypeName("");
        fruitAvailabilityListResponse.setSalesVolume(0.0D);
        fruitAvailabilityListResponse.setSalesAmount(newBigDecimal("0"));
        resultList.add(fruitAvailabilityListResponse);returnnewArrayList<>(resultList);}@OverridepublicDoublegetObtainInventory(StatisticsRequest statisticsRequest){return334423423.44;}}
importcom.mxf.code.strategy_factory.request.StatisticsRequest;importcom.mxf.code.strategy_factory.response.BaseResponse;importcom.mxf.code.strategy_factory.response.MeatAvailabilityListResponse;importcom.mxf.code.strategy_factory.service.AnalysisTableService;importorg.springframework.stereotype.Service;importjava.math.BigDecimal;importjava.util.ArrayList;importjava.util.List;/**
 * @author mxf
 * @version 1.0
 * @description: 肉
 * @date 2023/5/26
 */@Service("meatAnalysisTableService")publicclassMeatAnalysisTableServiceImplimplementsAnalysisTableService{@OverridepublicList<BaseResponse>getChartData(StatisticsRequest requestParams){returnnull;}@OverridepublicList<BaseResponse>getListData(StatisticsRequest statisticsRequest){List<MeatAvailabilityListResponse> resultList =newArrayList<>();MeatAvailabilityListResponse meatAvailabilityListResponse =newMeatAvailabilityListResponse();
        meatAvailabilityListResponse.setXDate("");
        meatAvailabilityListResponse.setMeatTypeName("");
        meatAvailabilityListResponse.setSalesVolume(0.0D);
        meatAvailabilityListResponse.setSalesAmount(newBigDecimal("0"));
        resultList.add(meatAvailabilityListResponse);returnnewArrayList<>(resultList);}}
importcom.mxf.code.strategy_factory.request.StatisticsRequest;importcom.mxf.code.strategy_factory.response.BaseResponse;importcom.mxf.code.strategy_factory.response.VegetableAvailabilityListResponse;importcom.mxf.code.strategy_factory.service.AnalysisTableService;importorg.springframework.stereotype.Service;importjava.math.BigDecimal;importjava.util.ArrayList;importjava.util.List;/**
 * @author mxf
 * @version 1.0
 * @description: 蔬菜
 * @date 2023/5/26
 */@Service("vegetableAnalysisTableService")publicclassVegetableAnalysisTableServiceImplimplementsAnalysisTableService{@OverridepublicList<BaseResponse>getChartData(StatisticsRequest requestParams){returnnull;}@OverridepublicList<BaseResponse>getListData(StatisticsRequest statisticsRequest){List<VegetableAvailabilityListResponse> resultList =newArrayList<>();VegetableAvailabilityListResponse vegetableAvailabilityListResponse =newVegetableAvailabilityListResponse();
        vegetableAvailabilityListResponse.setXDate("");
        vegetableAvailabilityListResponse.setVegetableName("");
        vegetableAvailabilityListResponse.setSalesVolume(0.0D);
        vegetableAvailabilityListResponse.setSalesAmount(newBigDecimal("0"));
        resultList.add(vegetableAvailabilityListResponse);returnnewArrayList<>(resultList);}}

3.8.控制层

importcom.mxf.code.strategy_factory.request.StatisticsRequest;importcom.mxf.code.strategy_factory.response.BaseResponse;importcom.mxf.code.strategy_factory.service.AnalysisTableService;importcom.mxf.code.strategy_factory.service.AnalysisTableStrategyContext;importcom.mxf.code.strategy_factory.service.FruitAnalysisTableService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.util.Assert;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.List;/**
 * @author mxf
 * @version 1.0
 * @description: 统计分析
 * @date 2023/5/26
 */@RestController@RequestMapping("statistical/indicators")publicclassStatisticalIndicatorsController{@AutowiredprivateAnalysisTableStrategyContext analysisTableStrategyContext;@AutowiredprivateFruitAnalysisTableService fruitAnalysisTableService;@GetMapping("listData")publicList<BaseResponse>getListData(StatisticsRequest statisticsRequest){AnalysisTableService resource = analysisTableStrategyContext.getResource(statisticsRequest.getStatisticalIndicatorsEnum());Assert.notNull(resource,"未知策略");return resource.getListData(statisticsRequest);}@GetMapping("chartData")publicList<BaseResponse>getchartData(StatisticsRequest statisticsRequest){AnalysisTableService resource = analysisTableStrategyContext.getResource(statisticsRequest.getStatisticalIndicatorsEnum());Assert.notNull(resource,"未知策略");return resource.getChartData(statisticsRequest);}@GetMapping("getFruitObtainInventory")publicDoublegetFruitObtainInventory(StatisticsRequest statisticsRequest){return fruitAnalysisTableService.getObtainInventory(statisticsRequest);}}

六、PostMan测试

1.测试getListData()接口

@GetMapping("listData")publicList<BaseResponse>getListData(StatisticsRequest statisticsRequest){AnalysisTableService resource = analysisTableStrategyContext.getResource(statisticsRequest.getStatisticalIndicatorsEnum());Assert.notNull(resource,"未知策略");return resource.getListData(statisticsRequest);}

在这里插入图片描述


2.测试getChartData()接口

@GetMapping("chartData")publicList<BaseResponse>getchartData(StatisticsRequest statisticsRequest){AnalysisTableService resource = analysisTableStrategyContext.getResource(statisticsRequest.getStatisticalIndicatorsEnum());Assert.notNull(resource,"未知策略");return resource.getChartData(statisticsRequest);}

在这里插入图片描述


3.getObtainInventory()扩展接口

@GetMapping("getFruitObtainInventory")publicDoublegetFruitObtainInventory(StatisticsRequest statisticsRequest){return fruitAnalysisTableService.getObtainInventory(statisticsRequest);}

在这里插入图片描述


总结

上述案例实现策略模式同时,针对入参、出参、接口扩展做了更好的兼容。


本文转载自: https://blog.csdn.net/weixin_44063083/article/details/130887384
版权归原作者 学不思则罔 所有, 如有侵权,请联系我们删除。

“策略模式-类型统计”的评论:

还没有评论