策略模式

场景假设

当前界面是一个工资计算器,不同的角色有不同的计算逻辑,比如有三种角色:老师、院长、校长。在这个界面上可以选择角色、输入请假天数、输入工龄,自动计算出本月工资。

通常写法

class SalaryCalculator
public static final int ROLE_TEACHER = 1;
public static final int ROLE_DEAN = 2;
public static final int ROLE_PRESIDENT = 3;

private int role;
private int leaveCount;//请假天数
private int workYear;
private int salary;
private int baseSalary;
//...
if(role== ROLE_TEACHER) {
    baseSalary = workYear*100+10000; //1年工龄月薪+100
} else if(role== ROLE_DEAN) {
    if(workYear >= 10) {
        baseSalary = workYear*300+20000;
    } else {
        baseSalary = workYear*200+20000;
    }
} else {
    baseSalary = workYear*500+30000;
}
//...为什么不把上下2个if else里面的代码合并起来,因为这只是DEMO,简单化了真实场景,真实场景比如这2段代码都需要各自在不同的回调里处理呢
if(role== ROLE_TEACHER) {
    salary = baseSalary/23*(23 - leaveCount);
} else if(role== ROLE_DEAN) {
    leaveCount = Math.max(leaveCount - 2, 0); //院长每个月有额外的2天假期
    salary = baseSalary/23*(23 - leaveCount);
} else {
    // 校长请假有半薪,且每个月有额外的3天假期
    leaveCount = Math.max(leaveCount - 3, 0);
    salary = baseSalary/23*(23-leaveCount)+ baseSalary/23/2*leaveCount; 
}
//...

策略模式

class SalaryCalculator
public static final int ROLE_TEACHER = 1;
public static final int ROLE_DEAN = 2;
public static final int ROLE_PRESIDENT = 3;

private int role;
private int leaveCount;//请假天数
private int salary;
private SalaryStrategy strategy;
//...
if(role== ROLE_TEACHER) {
   strategy = new TeacherSalaryStrategy ();
} else if(role== ROLE_DEAN) {
   strategy = new DeanSalaryStrategy ();
} else {
   strategy = new PresidentSalaryStrategy ();
}
//..
strategy.setWorkYear(workYear);
//...
strategy.setLeaveCount(leaveCount);
salary = strategy.getSalary();
//...
interface SalaryStrategy
private void setWorkYear();
private void setLeaveCount();
private int getSalary();

这个可以用接口,当然也可以用抽象类,抽象类里面还能封装一些基本的公共的代码。

class TeacherSalaryStrategy implements SalaryStrategy
private int baseSalary=10000;
private int salary;

private void setWorkYear(int workYear){
    baseSalary = workYear*100+salary;
}

private void setLeaveCount(int leaveCount){
    salary = baseSalary/23*(23 - leaveCount);
}

private int getSalary(){
    if(salary==0){
        salary = baseSalary;
    }
    return salary;
}

另外2个类,院长和校长的,自己想吧。

总结:
使用了策略模式后,SalaryCalculator类里面只会出现一次if else
的角色判断,明显简洁了很多。这样后续有对薪资算法的修改,就不用改SalaryCalculator类了,有针对性的去不同角色的策略类里面修改就可以了。
当你看到一个类里面出现多次相同的判断条件,如例子中出现2次
if(role== ROLE_TEACHER) {
} else if(role==ROLE_DEAN) {
} else {
}
(虽然DEMO只有2次,但是可以继续假设场景,写出N次if else)
就要考虑是否能把代码合并在同一个if else里,是否要使用策略模式。

推荐阅读更多精彩内容