使用责任链和构造类的方法降低多条件if语句的圈复杂度。
场景:根据对象年龄判断年龄阶段,有如下5种情况。童年(0-6),少年(7-17),青年(18-40),中年(41-65),老年(>66)。因此if语句需要有5个分支和return语句会增加函数的圈复杂度。
重构前代码如下:
年龄范围枚举类
public enum AgeRangeEnum {
CHILD_MIN(0),
CHILD_MAX(6),
TEEN_MIN(7),
TEEN_MAX(17),
YOUNG_MIN(18),
YOUNG_MAX(40),
MIDDLE_MIN(41),
MIDDLE_MAX(65),
OLD_MIN(66),
OLD_MAX(Integer.MAX_VALUE);
private final Integer age;
AgeRangeEnum(Integer age) {
this.age = age;
}
public Integer getValue() {
return age;
}
}
年龄阶段枚举类
public enum StageEnum {
CHILD("童年"),
TEEN("少年"),
YOUNG("青年"),
MIDDLE("中年"),
OLD("老年");
private final String stage;
StageEnum(String stage){
this.stage = stage;
}
public String getStage(){
return stage;
}
}
重构前的函数
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class Human {
private Integer age;
// 重构前,多区间范围查询判断
public String getStageByAge(){
if(isChild()){
return StageEnum.CHILD.getStage();
}
if(isTeen()){
return StageEnum.TEEN.getStage();
}
if(isYoung()){
return StageEnum.YOUNG.getStage();
}
if(isMiddle()){
return StageEnum.MIDDLE.getStage();
}
return StageEnum.OLD.getStage();
}
public boolean isChild(){
return age >= AgeRangeEnum.CHILD_MIN.getValue() && age <= AgeRangeEnum.CHILD_MAX.getValue();
}
public boolean isTeen(){
return age >= AgeRangeEnum.TEEN_MIN.getValue() && age <= AgeRangeEnum.TEEN_MAX.getValue();
}
public boolean isYoung(){
return age >= AgeRangeEnum.YOUNG_MIN.getValue() && age <= AgeRangeEnum.YOUNG_MAX.getValue();
}
public boolean isMiddle(){
return age >= AgeRangeEnum.MIDDLE_MIN.getValue() && age <= AgeRangeEnum.MIDDLE_MAX.getValue();
}
public boolean isOld(){
return age > AgeRangeEnum.OLD_MIN.getValue() && age <= AgeRangeEnum.OLD_MAX.getValue();
}
}
使用构造类进行重构
自定义AgeRange类,属性包括年龄段上下限和阶段描述,一个方法判断给定年龄是否在当前范围内,提供静态方法给外部类调用通过年龄来获取当前年龄阶段,静态属性初始化AgeRange数组。
public class AgeRange {
private static final AgeRange[] AGE_RANGES = {
new AgeRange(AgeRangeEnum.CHILD_MIN.getValue(), AgeRangeEnum.CHILD_MAX.getValue(), StageEnum.CHILD.getStage()),
new AgeRange(AgeRangeEnum.TEEN_MIN.getValue(), AgeRangeEnum.TEEN_MAX.getValue(), StageEnum.TEEN.getStage()),
new AgeRange(AgeRangeEnum.YOUNG_MIN.getValue(), AgeRangeEnum.YOUNG_MAX.getValue(), StageEnum.YOUNG.getStage()),
new AgeRange(AgeRangeEnum.MIDDLE_MIN.getValue(), AgeRangeEnum.MIDDLE_MAX.getValue(), StageEnum.MIDDLE.getStage()),
new AgeRange(AgeRangeEnum.OLD_MIN.getValue(), AgeRangeEnum.OLD_MAX.getValue(), StageEnum.OLD.getStage())
};
private final Integer MIN;
private final Integer MAX;
private final String STAGE;
private AgeRange(Integer min, Integer max, String stage) {
this.MIN = min;
this.MAX = max;
this.STAGE = stage;
}
public static String getSTAGE(Integer age) {
for (AgeRange ageRange : AGE_RANGES) {
if (ageRange.contains(age)) {
return ageRange.STAGE;
}
}
return null;
}
private boolean contains(Integer age) {
return age >= MIN && age <= MAX;
}
}
外部调用:
public class Human {
private Integer age;
// 构造类重构
public String getStageByAge(){
return AgeRange.getSTAGE(age);
}
}
使用责任链模式进行重构
StageHandler抽象类:
public abstract class StageHandler {
protected StageHandler nextHandler;
public void setNextHandler(StageHandler nextHandler){
this.nextHandler = nextHandler;
}
public abstract String handle(Integer age);
}
需要写五个处理类,以ChildStageHandler为例:
@NoArgsConstructor
public class ChildStageHandler extends StageHandler {
@Override
public String handle(Integer age) {
if (isChild(age)) {
return StageEnum.CHILD.getStage();
} else {
return nextHandler.handle(age);
}
}
public boolean isChild(Integer age) {
return age >= AgeRangeEnum.CHILD_MIN.getValue() && age <= AgeRangeEnum.CHILD_MAX.getValue();
}
}
主方法构造处理链调用:
public class Human {
private Integer age;
// 责任链重构
public String getStageByAge() {
ChildStageHandler childStageHandler = new ChildStageHandler();
TeenStageHandler teenStageHandler = new TeenStageHandler();
YoungStageHandler youngStageHandler = new YoungStageHandler();
MiddleStageHandler middleStageHandler = new MiddleStageHandler();
OldStageHandler oldStageHandler = new OldStageHandler();
childStageHandler.setNextHandler(teenStageHandler);
teenStageHandler.setNextHandler(youngStageHandler);
youngStageHandler.setNextHandler(middleStageHandler);
middleStageHandler.setNextHandler(oldStageHandler);
return childStageHandler.handle(age);
}
}