还在写一大堆if/else吗?快来体验策略模式吧

1,121 阅读3分钟

为什么要替代if/else

开发过程中避免不了使用if/else进行逻辑判断,如果逻辑很复杂、判断逻辑会频繁改动或者后期会增加判断逻辑,那么if/else会导致代码很难理解且难以维护,建议大家采用策略模式来代替if/else

策略模式

将非固定功能抽取出来,独立定义接口和实现类,在Manager类中聚合,实现组装类的效果,达到以下效果:

  1. 可读性,编程规范性,便于其他程序员阅读和理解
  2. 可扩展性,可维护性,需要添加新功能时,非常方便,成本低
  3. 可靠性,添加新功能或减少功能后,对原有功能没有影响
  4. 满足开闭原则

示例

假设有这样的一个需求,根据员工上个月迟到和加班次数来计算奖金,如果迟到>=3次就每次扣100元,如果加班>5次就每次加50元,这个需求不管是否合理,只是一种假设。

先定义一个对象来记录迟到和加班的次数

StaffData staffData = StaffData.builder()
    .chidao(3)
    .jiaban(10)
    .build();

使用if/else的代码如下:

public static int calc(StaffData staffData) {
    int total = 0;
    if (staffData.getChidao() != null && staffData.getChidao() >= 3) {
        total -= staffData.getChidao() * 100;
    }
    if (staffData.getJiaban() != null && staffData.getJiaban() > 5) {
        total += staffData.getJiaban() * 50;
    }
    return total;
}

System.out.println("奖金=" + calc(staffData));

如果后期增加了需求,在StaffData中添加请假次数,请假超过3次则每次扣100元的规则,那么需要继续在calc方法中添加if

如果又要新增一个规则,在StaffData中添加迟到次数和基本工资,请假超过5次,迟到超过5次,直接扣基本工资的一半,仍然需要在calc方法中添加代码,最后calc方法会越来越复杂,日积月累之后很难再去维护,修改不当还会导致原先的逻辑发生错误

采用策略模式

先定义一个Policy接口,通常定义canApply方法来进行逻辑判断,定义apply方法执行相应的业务逻辑

public interface Policy {
    /**
     * 当前策略是否匹配
     *
     * @param data
     * @return
     */
    boolean canApply(StaffData data);

    /**
     * 执行策略
     *
     * @param data
     * @return
     */
    int apply(StaffData data);
}

定义一个策略管理类,这个类负责注入所有策略,然后对外提供一个apply方法,遍历调用所有的策略,并做相应的处理,简化外部调用

@Component
public class PolicyManager {
    @Autowired
    private List<Policy> policies;

    public int apply(StaffData data) {
        int total = 0;
        for (Policy policy : policies) {
            if (policy.canApply(data)) {
                total += policy.apply(data);
            }
        }
        return total;
    }
}

接下来可以定义需要的策略了

/**
 * 规则如果迟到>=3次就匹配
 */

@Component
public class Test1Policy implements Policy {
    @Override
    public boolean canApply(StaffData data) {
        return data.getChidao() != null && data.getChidao() >= 3;
    }

    @Override
    public int apply(StaffData data) {
        // 迟到1次扣100
        return -data.getChidao() * 100;
    }
}

再定义一个策略

/**
 * 如果加班超过5次就匹配
 */

@Component
public class Test2Policy implements Policy {
    @Override
    public boolean canApply(StaffData data) {
        return data.getJiaban() != null && data.getJiaban() > 5;
    }

    @Override
    public int apply(StaffData data) {
        // 加班1次加50
        return data.getJiaban() * 50;
    }
}

最后测试一下逻辑是否正确

@SpringBootApplication
public class PolicyTest {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(PolicyTest.class, args);
        PolicyManager manager = context.getBean(PolicyManager.class);

        StaffData staffData = StaffData.builder()
                .chidao(3)
                .jiaban(10)
                .build();
        System.out.println("奖金=" + manager.apply(staffData));
    }
}

后期添加计算规则时新增一个策略类就可以实现,不用去修改原先写好的策略类,代码也很清晰,各个策略类只负责自己要处理的业务