设计模式之策略模式

策略模式

策略模式属于行为型模式
概述:在日常开发中,会存在这样一个场景,根据用户请求的参数类型来调用不同的处理逻辑,而大多数开发者遇到这样的场景会优先使用if else 分支来处理这样的业务需求,如果需求迭代过程中,添加了新的类型,就需要在原来的代码上添加新的分支,这样就违背了开闭原则。本篇文章通过一个例子来介绍策略模式的概念和使用方法。

定义:策略模式是定义了一系列的算法,并且将其封装起来,使得这些算法可以相互替换,且不会相互影响。

  • 抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
  • 具体策略角色:包装了相关的算法和行为。
  • 环境角色:持有一个策略类的引用,最终给客户端调用

计算物流费用的例子

获取快递费用,我们在寄快递的时候,选择不同的快递公司,所需要的运费不一样,例如(简单打比方):中通的首重价8元,续重价3元,而圆通的的首重价10元,续重价2元。

代码实现

  • 业务方法
@Service
public class FreightService {

    private int YTInitFreight = 10;
    private int ZTInitFreight = 8;
    public String getFreightByType(String typeCode, Integer weight) {
    	//获取物流公司类型枚举
        FreightType type = FreightType.getByCode(typeCode);
        Integer result = 0;
        if(FreightType.YT.equals(type)){
            //圆通的计算逻辑
            result = weight - 1 > 0 ? (weight - 1) * 2 + YTInitFreight : YTInitFreight;
        }else if(FreightType.ZT.equals(type)){
            //中通的计算逻辑
            result = weight - 1 > 0 ? (weight - 1) * 2 + ZTInitFreight : ZTInitFreight;
        }if else {
			// 业务迭代时,添加其他类型快递公司须添加新的分支
		}else{
            return "运费类型不正确";
        }
        return result.toString();
    }
}
  • 前端入口
public String calculationFreight(@RequestParam String typeCode,
                                      @RequestParam Integer weight){
        return freightService.getFreightByTypeV2(typeCode,weight);
    }

测试

在这里插入图片描述
以上的例子,通过if else 可以实现我们的需求,但是每当有添加新的快递公司需求时,都需要在原来的代码上新增分支代码,现在的业务代码只是简单的,在实际的开发中,业务逻辑代码远远比这多,如果快递公司少时,还能接受,但一增多,这个方法的代码也会直线增加,影响美观,降低可读性,而且不符合”开闭原则“。

使用策略模式改造以上的例子

接下来,我们使用策略模式来改造以上的例子。

改造代码

  • 接口(抽象策略角色)
    定义一个接口,接口提供两个方法,判断是否使用当前计算快递费用的方法和计算快递费用的方法
public interface FreightIface {
    // 根据重量计算快递费用
    public Integer calculateFright(Integer weight);
    // 根据类型编码判断是否使用当前计算逻辑
    public Boolean isCurrent(String typeCode);
}
  • 实现类(具体策略角色)
    实现了计算快递费用的接口,重写计算逻辑,根据不同的类型编写不同的逻辑
/**
*  圆通快递费用实现类
*/
@Service
public class ZTFreightService implements FreightIface{
    private int ZTInitFreight = 8;
    @Override
    public Integer calculateFright(Integer weight) {
        return weight - 1 > 0 ? (weight - 1) * 2 + ZTInitFreight : ZTInitFreight;
    }

    @Override
    public Boolean isCurrent(String typeCode) {
        return FreightType.ZT.equals(FreightType.getByCode(typeCode));
    }
}
/**
* 中通快递费用实现类
*/
@Service
public class ZTFreightService implements FreightIface{
    private int ZTInitFreight = 8;
    @Override
    public Integer calculateFright(Integer weight) {
        return weight - 1 > 0 ? (weight - 1) * 2 + ZTInitFreight : ZTInitFreight;
    }

    @Override
    public Boolean isCurrent(String typeCode) {
        return FreightType.ZT.equals(FreightType.getByCode(typeCode));
    }
}
  • 业务类改造(环境角色)
@Service
public class FreightService {

    @Autowired // 注入所有快递费用的实现类
    private List<FreightIface> freightIfaceList;
    
    public String getFreightByTypeV2(String typeCode, Integer weight) {
        //根据类型得到对应的计算快递费用的实现类
        FreightIface freightIface = freightIfaceList.stream()
        .filter(f -> f.isCurrent(typeCode)).findFirst().orElse(null);
        if (freightIface == null) {
            return "运费类型不正确";
        }
        return freightIface.calculateFright(weight).toString();
    }
}

测试

测试结果和改造前的一样
通过使用策略模式,可以很好的避免了if else 结构编码,如果新加了快递公司,只需要添加新的实现类,并重写接口方法即可,符合”开闭原则“。

总结

优点

  • 具体策略角色直接可以相互替换;
  • 添加新的策略只需要添加新的实现类即可,不需要修改原来的代码;
  • 避免了过多的if else 分支结构。

缺点

  • 容易造成类爆炸。

使用场景

  • 需要在不同的场景下使用不同的算法(策略),或者该业务会迭代使用其他的方式实现。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值