一、场景
有两家商户分别为A商户和B商户,需要根据两家商户各自的配送费计算规则计算出配送费,A商家的规则为小于5km需按照每公里2元计算,超过5公里需按照每公里3元计算;B商家的规则为小于10km每公里按照1元计算,大于5km按照每公里3元计算。
二、实现
1、不引入策略模式的写法
(1)定义一个Controller和接受参数实体类
@RestController
@RequestMapping("/pay")
public class PayController {
@Autowired
private PayService payService;
@PostMapping
public BigDecimal computePrice(ComputeParam computeParam){
return payService.computePrice(computeParam);
}
}
public class ComputeParam {
public enum Type {
A_SHOP(1L,"A商户"),
B_SHOP(2L,"B商户");
private Long type;
private String name;
public static String getName(Long type){
for (Type value : Type.values()) {
if(type.equals(value.getType())){
return value.getName();
}
}
return null;
}
public Long getType() {
return type;
}
public void setType(Long type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Type(Long type, String name) {
this.type = type;
this.name = name;
}
}
/**
* 距离
*/
private BigDecimal journeyDistance;
/**
* 商户类别
*/
private Long type;
public BigDecimal getJourneyDistance() {
return journeyDistance;
}
public void setJourneyDistance(BigDecimal journeyDistance) {
this.journeyDistance = journeyDistance;
}
public Long getType() {
return type;
}
public void setType(Long type) {
this.type = type;
}
public ComputeParam(BigDecimal journeyDistance, Long type) {
this.journeyDistance = journeyDistance;
this.type = type;
}
public ComputeParam() {
}
}
(2)定义一个Service及实现类
public interface PayService {
/**
* 计算价格
* @param computeParam
* @return
*/
BigDecimal computePrice(ComputeParam computeParam);
}
@Service
public class PayServiceImpl implements PayService {
@Override
public BigDecimal computePrice(ComputeParam computeParam) {
if (computeParam.getType().equals(ComputeParam.Type.A_SHOP.getType())){
// 小于5km,按照每公里2元计算
if (computeParam.getJourneyDistance().compareTo(new BigDecimal(5)) < 0) {
return computeParam.getJourneyDistance().multiply(new BigDecimal(2));
}
// 大于5km,按照每公里3元计算
return computeParam.getJourneyDistance().multiply(new BigDecimal(3));
}else if (computeParam.getType().equals(ComputeParam.Type.B_SHOP.getType())){
// 小于10km,按照每公里1元计算
if (computeParam.getJourneyDistance().compareTo(new BigDecimal(10)) < 0) {
return computeParam.getJourneyDistance().multiply(new BigDecimal(1));
}
// 大于5km,按照每公里3元计算
return computeParam.getJourneyDistance().multiply(new BigDecimal(5));
}
}
}
可见上面实现类中的computePrice方法,如果存在多个商户我们就要写多个if语句去判断,这样的代码显然不够优雅,而且不方便我们后期维护,如果这个计算方法在多处用到,我们就需要每次改一个方法就要改多处方法,显然不方便而且让代码不易维护。所以引入了策略模式。
2、引入策略模式的写法
(1)增加一个Service用于计算的策略ComputedService接口
public interface ComputedService {
/**
* 判断是哪个商家
* @param type
* @return
*/
public Boolean judgeType(Long type);
/**
* 计算价格
* @param journeyDistance
* @return
*/
public BigDecimal computePrice(BigDecimal journeyDistance);
}
说明:judge()方法为判断是否是哪个商家,用于等等查找是哪个策略使用到,computePrice()方法就是计算价格
(2)增加两个A商户和B商户的计算策略实现类去实现策略ComputedService接口
A商户
@Service
public class AShopComputed implements ComputedService {
@Override
public Boolean judgeType(Long type) {
return Objects.equals(type, ComputeParam.Type.A_SHOP.getType());
}
@Override
public BigDecimal computePrice(BigDecimal journeyDistance) {
// 小于5km,按照每公里2元计算
if (journeyDistance.compareTo(new BigDecimal(5)) < 0) {
return journeyDistance.multiply(new BigDecimal(2));
}
// 大于5km,按照每公里3元计算
return journeyDistance.multiply(new BigDecimal(3));
}
}
B商户
@Service
public class BShopComputed implements ComputedService {
@Override
public Boolean judgeType(Long type) {
return Objects.equals(type, ComputeParam.Type.B_SHOP.getType());
}
@Override
public BigDecimal computePrice(BigDecimal journeyDistance) {
// 小于10km,按照每公里1元计算
if (journeyDistance.compareTo(new BigDecimal(10)) < 0) {
return journeyDistance.multiply(new BigDecimal(1));
}
// 大于10km,按照每公里5元计算
return journeyDistance.multiply(new BigDecimal(5));
}
}
(3)改造后的Service类代码
@Service
public class PayServiceImpl implements PayService {
@Autowired
private List<ComputedService> computedServices;
@Override
public BigDecimal computePrice(ComputeParam computeParam) {
ComputedService computedService = computedServices.stream().filter(item -> item.judgeType(computeParam.getType()))
.findFirst().orElse(null);
if (ObjectUtils.isEmpty(computedService)){
throw new RuntimeException("没有找到该商户信息");
}
return computedService.computePrice(computeParam.getJourneyDistance());
}
}
说明:
1、我们需要注入一个策略集合
2、通过judgeType()方法去找出传进来的type参数为哪个商户
3、判断完后调用对应的计算方法计算出价格
三、总结
策略模式不仅可以减少我们对if-else的写法,更加利于对代码的维护,之后如果需求引入C商户、D商户等等,我们只需要编写对应的策略类去实现策略接口就可以,不需要在改动计算内部的实现类方法,更加利于扩展。