在做统计的业务开发中,常常伴随着用户选择不同类型的统计而动态的加载数据,返回的数据也会动态的改变,比如说一张商超里面可能有贩卖肉蛋禽、蔬菜、饮料、水果等,我们需要根据这几种类型指标(算法不同)去生成各自的统计数据,如果根据不同的类型写不同的接口,可以实简单现该功能,但带来的问题是接口定义太多,重复方法定义过多,如果统一一个接口、内容使用if去走分支,也可以实现相同的效果,但还是不够理想化,理想的是不需要手动的添加if分支,而是做到自动匹配到对应算法执行指定的流程,那么这时候就需要策略模式来帮我们实现这一步操作了
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum StatisticalIndicatorsEnum {
/**
* 肉
*/
MEAT(1, "肉", "meatAnalysisTableService"),
/**
* 水果
*/
FRUIT(2, "水果", "fruitAnalysisTableService"),
/**
* 蔬菜
*/
VEGETABLE(3, "蔬菜", "vegetableAnalysisTableService"),
/**
* 饮料
*/
BEVERAGE(4, "饮料", "beverageAnalysisTableService");
/**
* 编码
*/
private final Integer code;
/**
* 注释
*/
private final String desc;
/**
* 对应策略
*/
private final String strategyName;
}
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mxf.code.strategy_factory.enums.StatisticalIndicatorsEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.web.bind.annotation.ModelAttribute;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
/**
* 统计图Request
*/
@Data
@ApiModel(value = "统计图Request")
public class StatisticsRequest implements Serializable {
private static final long serialVersionUID = 1L;
@NotBlank(message = "统计指标不能为空")
@ApiModelProperty(value = "统计指标")
private StatisticalIndicatorsEnum statisticalIndicatorsEnum;
@NotNull(message = "统计起始时间不能为空")
@ApiModelProperty(value = "开始时间,格式:yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date startDate;
@NotNull(message = "统计截止时间不能为空")
@ApiModelProperty(value = "结束时间(格式:yyyy-MM-dd)")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date endDate;
@ModelAttribute("statisticalIndicators")
public void setStatisticalIndicatorsEnum(StatisticalIndicatorsEnum statisticalIndicatorsEnum) {
this.statisticalIndicatorsEnum = statisticalIndicatorsEnum;
}
}
import lombok.Data;
/**
* @author mxf
* @version 1.0
* @description: 响应体Base
* @date 2023/5/26
*/
@Data
public abstract class BaseResponse {
}
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author 28382
*/
@Data
@ApiModel(value = "蔬菜")
@EqualsAndHashCode(callSuper = true)
public class BeverageAvailabilityListResponse extends BaseResponse implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "统计时间")
private String xDate;
@ApiModelProperty(value = "饮料类型名称")
private String beverageTypeName;
@ApiModelProperty(value = "销售件数")
private Double salesQuantity;
@ApiModelProperty(value = "销售金额")
private BigDecimal salesAmount;
}
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author 28382
*/
@Data
@ApiModel(value = "水果图表响应体")
@EqualsAndHashCode(callSuper = true)
public class FruitAvailabilityChartResponse extends BaseResponse implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "统计时间")
private String xDate;
@ApiModelProperty(value = "本年销售总额")
private BigDecimal currentYearSalesAmount;
@ApiModelProperty(value = "去年销售金额")
private BigDecimal previousYearSalesAmount;
}
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author 28382
*/
@Data
@ApiModel(value = "水果")
@EqualsAndHashCode(callSuper = true)
public class FruitAvailabilityListResponse extends BaseResponse implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "统计时间")
private String xDate;
@ApiModelProperty(value = "肉类名")
private String fruitTypeName;
@ApiModelProperty(value = "销售量kg")
private Double salesVolume;
@ApiModelProperty(value = "销售金额")
private BigDecimal salesAmount;
}
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author 28382
*/
@Data
@ApiModel(value = "肉")
@EqualsAndHashCode(callSuper = true)
public class MeatAvailabilityListResponse extends BaseResponse implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "统计时间")
private String xDate;
@ApiModelProperty(value = "肉类名")
private String meatTypeName;
@ApiModelProperty(value = "销售量kg")
private Double salesVolume;
@ApiModelProperty(value = "销售金额")
private BigDecimal salesAmount;
}
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author 28382
*/
@Data
@ApiModel(value = "蔬菜")
@EqualsAndHashCode(callSuper = true)
public class VegetableAvailabilityListResponse extends BaseResponse implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "统计时间")
private String xDate;
@ApiModelProperty(value = "肉类名")
private String vegetableName;
@ApiModelProperty(value = "销售量kg")
private Double salesVolume;
@ApiModelProperty(value = "销售金额")
private BigDecimal salesAmount;
}
管理策略bean
import com.mxf.code.strategy_factory.enums.StatisticalIndicatorsEnum;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 分析统计指标策略
*
* @author 28382
*/
@Service
public class AnalysisTableStrategyContext {
private final Map<String, AnalysisTableService> analysisTableMap = new ConcurrentHashMap<>();
public AnalysisTableStrategyContext(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]
*/
public AnalysisTableService getResource(StatisticalIndicatorsEnum statisticalIndicatorsEnum) {
return analysisTableMap.get(statisticalIndicatorsEnum.getStrategyName());
}
}
import com.mxf.code.strategy_factory.request.StatisticsRequest;
import com.mxf.code.strategy_factory.response.BaseResponse;
import java.util.List;
/**
* 统计分析
*/
public interface AnalysisTableService {
/**
* 获取统计图数据
*
* @param requestParams 入参
* @return
*/
List<BaseResponse> getChartData(StatisticsRequest statisticsRequest);
/**
* 获取列表数据
*
* @param requestParams 入参
* @return
*/
List<BaseResponse> getListData(StatisticsRequest statisticsRequest);
}
import com.mxf.code.strategy_factory.request.StatisticsRequest;
/**
* @author mxf
* @version 1.0
* @description: 水果(自定义接口)
* @date 2023/5/26
*/
public interface FruitAnalysisTableService {
/**
* 获取水果库存
*
* @param statisticsRequest 入参
* @return
*/
Double getObtainInventory(StatisticsRequest statisticsRequest);
}
import com.mxf.code.strategy_factory.request.StatisticsRequest;
import com.mxf.code.strategy_factory.response.BaseResponse;
import com.mxf.code.strategy_factory.response.BeverageAvailabilityListResponse;
import com.mxf.code.strategy_factory.service.AnalysisTableService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @author mxf
* @version 1.0
* @description: 饮料
* @date 2023/5/26
*/
@Service("beverageAnalysisTableService")
public class BeverageAnalysisTableServiceImpl implements AnalysisTableService {
@Override
public List<BaseResponse> getChartData(StatisticsRequest requestParams) {
return null;
}
@Override
public List<BaseResponse> getListData(StatisticsRequest statisticsRequest) {
List<BeverageAvailabilityListResponse> resultList = new ArrayList<>();
BeverageAvailabilityListResponse beverageAvailabilityListResponse = new BeverageAvailabilityListResponse();
beverageAvailabilityListResponse.setXDate("");
beverageAvailabilityListResponse.setBeverageTypeName("");
beverageAvailabilityListResponse.setSalesQuantity(0.0D);
beverageAvailabilityListResponse.setSalesAmount(new BigDecimal("0"));
resultList.add(beverageAvailabilityListResponse);
return new ArrayList<>(resultList);
}
}
import com.mxf.code.strategy_factory.request.StatisticsRequest;
import com.mxf.code.strategy_factory.response.BaseResponse;
import com.mxf.code.strategy_factory.response.FruitAvailabilityChartResponse;
import com.mxf.code.strategy_factory.response.FruitAvailabilityListResponse;
import com.mxf.code.strategy_factory.service.AnalysisTableService;
import com.mxf.code.strategy_factory.service.FruitAnalysisTableService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @author mxf
* @version 1.0
* @description: 水果
* @date 2023/5/26
*/
@Service("fruitAnalysisTableService")
public class FruitAnalysisTableServiceImpl implements AnalysisTableService, FruitAnalysisTableService {
@Override
public List<BaseResponse> getChartData(StatisticsRequest requestParams) {
List<FruitAvailabilityChartResponse> resultList = new ArrayList<>();
FruitAvailabilityChartResponse fruitAvailabilityChartResponse = new FruitAvailabilityChartResponse();
fruitAvailabilityChartResponse.setXDate("2022-05-25");
fruitAvailabilityChartResponse.setCurrentYearSalesAmount(new BigDecimal("4"));
fruitAvailabilityChartResponse.setPreviousYearSalesAmount(new BigDecimal("5"));
FruitAvailabilityChartResponse fruitAvailabilityChartResponse2 = new FruitAvailabilityChartResponse();
fruitAvailabilityChartResponse2.setXDate("2022-05-26");
fruitAvailabilityChartResponse2.setCurrentYearSalesAmount(new BigDecimal("1"));
fruitAvailabilityChartResponse2.setPreviousYearSalesAmount(new BigDecimal("2"));
resultList.add(fruitAvailabilityChartResponse);
resultList.add(fruitAvailabilityChartResponse2);
return new ArrayList<>(resultList);
}
@Override
public List<BaseResponse> getListData(StatisticsRequest statisticsRequest) {
List<FruitAvailabilityListResponse> resultList = new ArrayList<>();
FruitAvailabilityListResponse fruitAvailabilityListResponse = new FruitAvailabilityListResponse();
fruitAvailabilityListResponse.setXDate("");
fruitAvailabilityListResponse.setFruitTypeName("");
fruitAvailabilityListResponse.setSalesVolume(0.0D);
fruitAvailabilityListResponse.setSalesAmount(new BigDecimal("0"));
resultList.add(fruitAvailabilityListResponse);
return new ArrayList<>(resultList);
}
@Override
public Double getObtainInventory(StatisticsRequest statisticsRequest) {
return 334423423.44;
}
}
import com.mxf.code.strategy_factory.request.StatisticsRequest;
import com.mxf.code.strategy_factory.response.BaseResponse;
import com.mxf.code.strategy_factory.response.MeatAvailabilityListResponse;
import com.mxf.code.strategy_factory.service.AnalysisTableService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @author mxf
* @version 1.0
* @description: 肉
* @date 2023/5/26
*/
@Service("meatAnalysisTableService")
public class MeatAnalysisTableServiceImpl implements AnalysisTableService {
@Override
public List<BaseResponse> getChartData(StatisticsRequest requestParams) {
return null;
}
@Override
public List<BaseResponse> getListData(StatisticsRequest statisticsRequest) {
List<MeatAvailabilityListResponse> resultList = new ArrayList<>();
MeatAvailabilityListResponse meatAvailabilityListResponse = new MeatAvailabilityListResponse();
meatAvailabilityListResponse.setXDate("");
meatAvailabilityListResponse.setMeatTypeName("");
meatAvailabilityListResponse.setSalesVolume(0.0D);
meatAvailabilityListResponse.setSalesAmount(new BigDecimal("0"));
resultList.add(meatAvailabilityListResponse);
return new ArrayList<>(resultList);
}
}
import com.mxf.code.strategy_factory.request.StatisticsRequest;
import com.mxf.code.strategy_factory.response.BaseResponse;
import com.mxf.code.strategy_factory.response.VegetableAvailabilityListResponse;
import com.mxf.code.strategy_factory.service.AnalysisTableService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @author mxf
* @version 1.0
* @description: 蔬菜
* @date 2023/5/26
*/
@Service("vegetableAnalysisTableService")
public class VegetableAnalysisTableServiceImpl implements AnalysisTableService {
@Override
public List<BaseResponse> getChartData(StatisticsRequest requestParams) {
return null;
}
@Override
public List<BaseResponse> getListData(StatisticsRequest statisticsRequest) {
List<VegetableAvailabilityListResponse> resultList = new ArrayList<>();
VegetableAvailabilityListResponse vegetableAvailabilityListResponse = new VegetableAvailabilityListResponse();
vegetableAvailabilityListResponse.setXDate("");
vegetableAvailabilityListResponse.setVegetableName("");
vegetableAvailabilityListResponse.setSalesVolume(0.0D);
vegetableAvailabilityListResponse.setSalesAmount(new BigDecimal("0"));
resultList.add(vegetableAvailabilityListResponse);
return new ArrayList<>(resultList);
}
}
import com.mxf.code.strategy_factory.request.StatisticsRequest;
import com.mxf.code.strategy_factory.response.BaseResponse;
import com.mxf.code.strategy_factory.service.AnalysisTableService;
import com.mxf.code.strategy_factory.service.AnalysisTableStrategyContext;
import com.mxf.code.strategy_factory.service.FruitAnalysisTableService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author mxf
* @version 1.0
* @description: 统计分析
* @date 2023/5/26
*/
@RestController
@RequestMapping("statistical/indicators")
public class StatisticalIndicatorsController {
@Autowired
private AnalysisTableStrategyContext analysisTableStrategyContext;
@Autowired
private FruitAnalysisTableService fruitAnalysisTableService;
@GetMapping("listData")
public List<BaseResponse> getListData(StatisticsRequest statisticsRequest) {
AnalysisTableService resource = analysisTableStrategyContext.getResource(statisticsRequest.getStatisticalIndicatorsEnum());
Assert.notNull(resource, "未知策略");
return resource.getListData(statisticsRequest);
}
@GetMapping("chartData")
public List<BaseResponse> getchartData(StatisticsRequest statisticsRequest) {
AnalysisTableService resource = analysisTableStrategyContext.getResource(statisticsRequest.getStatisticalIndicatorsEnum());
Assert.notNull(resource, "未知策略");
return resource.getChartData(statisticsRequest);
}
@GetMapping("getFruitObtainInventory")
public Double getFruitObtainInventory(StatisticsRequest statisticsRequest) {
return fruitAnalysisTableService.getObtainInventory(statisticsRequest);
}
}
@GetMapping("listData")
public List<BaseResponse> getListData(StatisticsRequest statisticsRequest) {
AnalysisTableService resource = analysisTableStrategyContext.getResource(statisticsRequest.getStatisticalIndicatorsEnum());
Assert.notNull(resource, "未知策略");
return resource.getListData(statisticsRequest);
}
@GetMapping("chartData")
public List<BaseResponse> getchartData(StatisticsRequest statisticsRequest) {
AnalysisTableService resource = analysisTableStrategyContext.getResource(statisticsRequest.getStatisticalIndicatorsEnum());
Assert.notNull(resource, "未知策略");
return resource.getChartData(statisticsRequest);
}
@GetMapping("getFruitObtainInventory")
public Double getFruitObtainInventory(StatisticsRequest statisticsRequest) {
return fruitAnalysisTableService.getObtainInventory(statisticsRequest);
}
上述案例实现策略模式同时,针对入参、出参、接口扩展做了更好的兼容。