Java策略模式实战例子

一、场景

        有两家商户分别为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商户等等,我们只需要编写对应的策略类去实现策略接口就可以,不需要在改动计算内部的实现类方法,更加利于扩展。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小小王w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值