使用策略模式替代if-else

前言

由于客户考勤有了新的改动,所以今天从公司服务器取出去年关于考勤代码,其中有一部分功能跟请假的相关,该公司目前的请假类型一共有14种,不同的请假类型会扣不同的基本分和绩效分,其中基本分数关系到工资,绩效分数关系到奖金。改动过程中发现自己代码写的有点混乱,而且现在新增的逻辑代码更是雪上加霜,所以有了今天这篇文章

正文

在最开始的时候我使用枚举来返回请假类型对应基本分数和绩效分数,如下代码。根据前台传来请假天数和请假类型,我这边乘上相应分数即可。

public enum LeaveType {
    leave1(1, "事假", 4, 2),
    leave2(2, "病假", 2, 1),
    leave5(5, "探亲假", 0, 2),
    leave6(6, "年假", 0, 1),
    leaver7(7, "婚嫁", 0, 0.5),
    leave8(8, "产假", 0, 0.5),
    leave9(9, "哺乳假", 0, 1),
    leave10(10, "丧假", 0, 1),
    leave11(11, "儿童陪护假", 0, 1),
    leave12(12, "带薪病假", 0, 1),
    leave13(13, "调休", 0, 0),
    leave14(14, "公差", 0, 0),
    leave15(15, "工伤假", 0, 0),
    leave16(16, "陪产假", 0, 0.1);

//请假类型标志
int type;
//请假名称
String desc;
//基本分数
double baseScore;
//绩效分数
double performanceScore;

LeaveType(int type, String desc, double baseScore, double performanceScore) {
this.type = type;
this.desc = desc;
this.baseScore = baseScore;
this.performanceScore = performanceScore;
}

public static double getBaseScore(double type) {
for (LeaveType t : values()) {
if (type == t.type) {
return t.baseScore;
}
}
return 0;
}

public static double getPerformanceScore(double type) {
for (LeaveType t : values()) {
if (type == t.type) {
return t.performanceScore;
}
}
return 0;
}

public int type() {
return type;
}
}

 

现在客户又要增加几种请假类型,同时有一些逻辑也要修改,比如:当前台传来请假天数小于0.5天的时候,此时病假不扣绩效分了,基本分照常扣减,而事假绩效扣的分值减半,基本分正常扣减。

之前逻辑如下:

  //基本分数
  double number = days*IllType.getBaseScore(typeTemp);
  //绩效分数
  double number2 = days*IllType.getPerformanceScore(typeTemp);

现在显然不可能了,我们要增加一些判断。这里我们简单看下,实际的扣减逻辑要比这个复杂

 double number =0;
 double number2 =0;
  if(type == 1){
      //如果是病假
        if (days < 0.5)
           number = days*IllType.getBaseScore(typeTemp)/2;
  }
  else if(type == 2){
      //如果是病假
        if (days < 0.5)
             number = 0;
  }else{
  //正常逻辑
 number = days*IllType.getBaseScore(typeTemp);
 number2 = days*IllType.getPerformanceScore(typeTemp);
  }

这里我们罗列出来两种请假类型的计算分值发生变化,但是如果后续又有改动,我又需要捋一遍这些判断,然后继续增加if-else,当if-else过多的时候,这对于维护会造成很大阻碍,所以我想有没有一种利于后期维护的方案呢?

百度得到答案大多都是使用策略模式,把业务逻辑都控制在每种情况的实体类中,这里我也参考下网上的方式使用策略模式来完成这次逻辑变动(说来惭愧,前面自己还写过策略模式的文章,但是仍然不会实际运用,可见学的东西要真的用起来才能融会贯通,只是学一些表面东西,很难有所突破)。

首先枚举类我们保持不变,增加考勤的抽象类,其中general和generalPerformanceScore方法是修改前计算分数方法,对于没有改动的请假子类我们调用这个方法就可以了。

public abstract class AbstractAttence {

//扣除的基本分
public abstract double reduceBaseScore(double days,int type);

//扣除的绩效分
public abstract double reducePerformanceScore(double days,int type);

/**
* 正常扣分逻辑
*
* @param days
* @param score
* @return
*/

public double general(double days, double score) {
return days * score;
}
public double generalPerformanceScore(double days, double type) {
return days * LeaveType.getPerformanceScore(type);
}
}

 

然后我们定义事假

//事假,如果请假天数小于0.2,那么基本扣分减半,绩效分计算规则不变
public class GeneralAttence extends AbstractAttence {

private static final GeneralAttence generalAttence = new GeneralAttence();

private GeneralAttence() {

}

public static GeneralAttence getGeneralAttence() {
return generalAttence;
}
@Override
public double reduceBaseScore(double days, int type) {
double score = LeaveType.getBaseScore(type);
if (days < 0.2)
score /= 2;
return days * score;
}

@Override
public double reducePerformanceScore(double days, int type) {
return generalPerformanceScore(days, type);
}
}

 

病假

//病假,如果请假天数小于0.5,那么绩效分不扣,基本分计算规则不变
public class SickAttence extends AbstractAttence {
    private static final SickAttence sickAttence = new SickAttence();

private SickAttence() {

}

public static SickAttence getSickAttence() {
return sickAttence;
}

@Override
public double reduceBaseScore(double days, int type) {
return general(days, type);
}

@Override
public double reducePerformanceScore(double days, int type) {
if (days < 0.5)
return 0;
return generalPerformanceScore(days, type);
}
}

 

我们将每一种请假定义为实体类,当请假扣分的逻辑发生变化时候,我们可以将其控制在每种类的内部,就省去很多判断,而且逻辑十分清晰,谁的逻辑改动我就去找谁,不像前面我们写在一起那么混乱。

最后我们定义策略工厂,用于保存这些实体类,

public class StrageFactory {

public Map<Integer, AbstractAttence> map = new HashMap<>();

public StrageFactory() {
map.put(LeaveType.leave1.type(), GeneralAttence.getGeneralAttence());
map.put(LeaveType.leave2.type(), SickAttence.getSickAttence());
//….这里省略其他请假类型
}

public AbstractAttence getAttence(int type) {
return map.get(type);
}

}

 

那么客户端调用

public class Client {
    public static void main(String[] args) {
        StrageFactory strageFactory = new StrageFactory();

//(1, “事假“, 4, 2),

AbstractAttence abstractAttence = strageFactory.getAttence(1);

System.out.println(abstractAttence.reduceBaseScore(1, 1));

System.out.println(abstractAttence.reducePerformanceScore(0.5, 1));

System.out.println(abstractAttence.reduceBaseScore(0.1, 1));

System.out.println(“===”);
//(2, “病假“, 2, 1)
abstractAttence = strageFactory.getAttence(2);

System.out.println(abstractAttence.reduceBaseScore(1, 2));

System.out.println(abstractAttence.reducePerformanceScore(1, 2));

System.out.println(abstractAttence.reducePerformanceScore(0.4, 2));

}
}

 

到这里我们就使用策略模式来替代if-else语句,优点很明显,

  • 每个算法单独封装,减少了算法和算法调用者的耦合
  • 合理使用继承有助于提取出算法中的公共部分。

但是缺点也很明显

  • 策略模式只适用于客户端知道所有的算法或行为的情况。
  • 策略模式造成很多的策略类,每个具体策略类都会产生一个新类。不过可以使用享元模式来减少对象的数量。

 

 

未经允许不得转载:996ICU » 使用策略模式替代if-else

赞 (0) 打赏