策略模式取代分支结构

问题描述

在多个接口长的一样的情况下,或者一个接口有多个实现类的情况下。使用策略模式(state/strategy)重构分支语句。

主要有两个方法:

  1. 创建枚举类;
  2. 在接口中定义用于返回区分各个实现类的channel()函数。

第一种枚举类的方法适用于实现类采用不同算法的情况,不需要使用@Autowired自动注入的情况;

第二种方法适用于需要自动注入,new一个实现类无法实现自动注入的情况。

先随便举个栗子作为重构前的代码:

switch(customer){
    case "common":
        price = commonCustomer.contPrice(productPrice,num);
        break;
    case "lv1":
        price = levelOneCustomer.contPrice(productPrice,num);
        break;
    case "lv2":
        price = levelTwoCustomer.contPrice(productPrice,num);
        break;
    case "VIP":
        price = VIPCustomer.contPrice(productPrice,num);
        break;
    default:
        break;
}

一个接口就对应了一个case,接口内的每一个函数往往都需要这样一个switch,这样每多一种情况就要在各个switch中查找修改,任务量大不说,还容易出错

创建枚举法

1.合并接口

在处理前接口和实现类往往是一对一关系,接口的存在意义仿佛被淡化了。将原先多个实现类合并为一个接口的实现类:

public interface CustomerService{
    Double contPrice(double productPrice,double num);
}

case分支的接口改为其实现类,这里选择VIPCustomer为例:

public class VIPCustomer implements CustomerService {
    @Override
    public Double contPrice(double productPrice,double num) {
        return 0.6 * productPrice * num;
    }
}

2.创建枚举类

public enum customerType {
  common,
  lv1,
  lv2,
  VIP;
}

3.创建Map

 public class PriceController {

  static Map<customerType, CustomerService> customerServiceMap = new HashMap<>();

  static {
      customerServiceMap.put(customerType.common,new commonCustomer());
      customerServiceMap.put(customerType.lv1,new levelOneCustomer());
      customerServiceMap.put(customerType.lv2,new levelTwoCustomer());
      customerServiceMap.put(customerType.VIP,new VIPCustomer());
  }

  public Double contPrice(String customerType,double productPrice,double num) {
    // 根据字符串顾客类型获取到对应的枚举类型  
    customerType customer = customerType.valueOf(customerType);
    // 从Map中拿到操作类型对应的策略类,如果没有,则默认返回DefaultTask,没有DefaultTask也可以直接用get
    CustomerService customerService = customerServiceMap.getOrDefault(customer, new DefaultTask());
    // 返回结果
    return customerService.contPrice(productPrice,num);
  }
}

以上改造适用于算法类,如果实现类还需要调用Mapper等操作,可能需要自动注入的,在static生成时,new出来的实现类无法实现自动注入,在运行时会出现空指针异常,请采用下面的方法。

返回标志法

将上面的栗子改为从数据库中查找商品对应的价格,则Impl类就变成下面这个样子:

public class VIPCustomer implements CustomerService {
    @Autowired
    productServiceMapper productMapper;
    
    @Override
    public Double contPrice(String productName,double num) {
        double productPrice = productMapper.getPriceByName(productName);
        return 0.6 * productPrice * num;
    }
}

此时由于需要@Autowired自动注入,之前new一个实现类由于静态代码在自动注入之前完成,因此无法实现自动注入。

1.集合保存实现类

首先通过Set<CustomerService>CustomerService接口的所有实现类都注入集合customerServiceSet中。

@Autowired
Set<CustomerService> customerServiceSet;

2.存储映射关系

接着使用Map<String, CustomerService>存储调用实现类和原先每个case之间的映射关系,并初始化

Map<String,CustomerService> customerServiceMap = new HashMap<>();

@PostConstruct
public void init() {
    for (CustomerService customerService : customerServiceSet) {
        customerServiceMap.put(customerService.channel(), customerService);
    }
}

使用@PostConstruct注解修饰的init方法会在Spring容器的启动时自动的执行,在其中完成映射Map的构建。

为避免看不懂这些代码放在哪,把完整的Controller写一下:

public class PriceController{
    @Autowired
	Set<CustomerService> customerServiceSet;
    
    Map<String,CustomerService> customerServiceMap = new HashMap<>();
    
    public Double contPrice(String customerType,double productPrice,double num) {
        // 根据字符串顾客类型获取到对应实现类
        CustomerService customerService = customerServiceMap.get(customerType);
        // 返回结果
        return customerService.contPrice(productPrice,num);
  }

    @PostConstruct
    public void init() {
        for (CustomerService customerService : customerServiceSet) {
            customerServiceMap.put(customerService.channel(), customerService);
        }
	}
}

3.接口定义返回标志

public interface CustomerService{
    Double contPrice(double productPrice,double num);
    
    String channel();
}

4.实现类区分返回值

public class VIPCustomer implements CustomerService {
    @Override
    public String channel(){
        return "VIP";
    }
}

大功告成!

参考文档

【设计模式】-- 使用策略模式重构switch case语句

spring boot 中如何优雅的使用自动注入实现策略模式

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值