还在写大量的if-else?如何通过策略模式优化你臃肿代码

801 阅读4分钟

这是我参与更文挑战的第10天,活动详情查看: 更文挑战

前言

  1. 如果你当前的系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为,那么请拥抱策略模式吧;
  2. 如果你的系统需要动态地在几种算法中选择一种,那么请拥抱策略模式吧;
  3. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现,那么请拥抱策略模式吧;

需求背景:

小编前端时间遇到的需求是这样的,上游服务会推送固定的几种key到我的当前系统,不会经常性的改变,而作为下游服务的我们,要针对每一种key去做一系列的业务操作;当然最先想到的就是switch case或者if-else 当然这样也是可行的,但是作为一个优“秀”的程序员,这符合我们的风格吗?不符合!一个字,我们得“支棱”起来啊,ok!接下来进行秀操作时刻(当然也不全是为了秀,策略模式也是有这他的优点的,它极其适合解决我们当前这样业务模式;

解决方案:

把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口,然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。

我们的的核思想其实喝if-else如出一辙,根据不同的key动态的找到不同的业务逻辑;通过策略模式 我们在代码结构上调整,用接口+实现类+分派逻辑来加强代码结构的可维护性;

下面我们使用一个例子来做介绍:

1、我们先创建一个Enum枚举类来吧我们需要维护的key都加入枚举之后新增和修改直接加枚举即可

/**
 * @author taoze
 * @version 1.0
 * @date 4/21/21 11:39 AM
 */
public enum CarEnum {
    BenzG500("G500","奔驰"),
    BMW320("320","宝马"),
    AoDi("A4","奥迪"),
    TOYOTA("凯美瑞","丰田");

    public String version;
    public String brand;

    CarEnum(String version,String brand) {
        this.version = version;
        this.brand = brand;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public static String getValue(String code) {
        for (CarEnum ele : values()) {
            if(ele.getBrand().equals(code)) return ele.getVersion();
        }
        return null;
    }
}

2、创建一个策略分配的基类,来进行策略分配

/**
 * 策略分配工厂
 *
 * @author taoze
 * @version 1.0
 * @date 6/8/21 5:27 PM
 */
@Component
@Slf4j
public class StrategyFactory {

    private Map<String, Function<String, String>> checkResultDispatcherComX = new HashMap<>();
    @Autowired
    private StrategyService strategyService;

    /**
     * 初始化 业务逻辑分派Map 其中value 存放的是 lambda表达式
     */
    @PostConstruct
    public void checkResultDispatcherComXInit() {
        checkResultDispatcherComX.put(CarEnum.AoDi.brand, code -> strategyService.buyAoDi(code));
        checkResultDispatcherComX.put(CarEnum.BenzG500.brand, code -> strategyService.buyBeanz(code));
        checkResultDispatcherComX.put(CarEnum.BMW320.brand, code -> strategyService.buyBMW(code));
        checkResultDispatcherComX.put(CarEnum.TOYOTA.brand, code -> strategyService.buyToyota(code));

    }

    public String getCheckResultComX(String key) {
        Function<String, String> result = checkResultDispatcherComX.get(key);
        if(result!=null){
            String apply = result.apply(key);
            return apply;
        }
        return null;
    }
}

3、分配策略业务实现接口

/**
 * 策略模式
 *
 * @author taoze
 * @version 1.0
 * @date 6/8/21 5:21 PM
 */
public interface StrategyService {

    String buyAoDi(String code);

    String buyBeanz(String code);

    String buyBMW(String code);

    String buyToyota(String code);
}

4、业务实现方法

/**
 *
 *
 * @author taoze
 * @version 1.0
 * @date 6/8/21 5:22 PM
 */
@Service
@Slf4j
public class StrategyServiceImpl implements StrategyService {

    @Override
    public String buyAoDi(String code) {
        System.out.println(CarEnum.getValue(code));
        return CarEnum.getValue(code);
    }

    @Override
    public String buyBeanz(String code) {
        System.out.println(CarEnum.getValue(code));
        return CarEnum.getValue(code);
    }

    @Override
    public String buyBMW(String code) {
        System.out.println(CarEnum.getValue(code));
        return CarEnum.getValue(code);
    }

    @Override
    public String buyToyota(String code) {
        System.out.println(CarEnum.getValue(code));
        return CarEnum.getValue(code);
    }
}

5、调用接口

 @GetMapping("/testStrategy")
    public WechatServerResult testStrategy(@RequestParam("key") String key) {
        log.info("param = {}",key);
        return WechatServerResult.build(() -> strategyFactory.getCheckResultComX(key));
    }

齐活~完事~ 图片.png

总结:

其实策略模式也并不是完美的,他有这自己缺点,我们在使用的时候也要考虑他的可维护性和实用性;当大量的新增策略,策略类会膨胀维护起来相对更加的复杂;

优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。

缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

ok!策略模式分享到这里了,大家可根据自身情况选择是否进行“秀”操作,希望可以对大家有帮助,有不对的地方希望大家可以提出来的,共同成长;

整洁成就卓越代码,细节之中只有天地