優(yōu)雅重構(gòu)if-else的12種方法
環(huán)境:Java21
1. 簡(jiǎn)介
在軟件開發(fā)中,過(guò)度依賴if-else會(huì)導(dǎo)致代碼難以維護(hù)、擴(kuò)展性差,形成所謂的“面條代碼”。隨著業(yè)務(wù)邏輯復(fù)雜化,嵌套條件判斷更會(huì)顯著降低可讀性與測(cè)試效率。
本篇文章匯總16+種經(jīng)過(guò)實(shí)踐驗(yàn)證的優(yōu)雅重構(gòu)方法,助你寫出更清晰、可維護(hù)的代碼。
2.實(shí)戰(zhàn)案例
2.1 刪除不必要的else語(yǔ)句
有些時(shí)候你會(huì)發(fā)現(xiàn)else語(yǔ)句塊根本沒有必要,如下示例:
public void remove_unnecessary_else_example(Integer input) {  
  if (input > 10) {  
    // ...
  } else {  
    // TODO else
  }  
}優(yōu)化后
public void remove_unnecessary_else_solution(Integer input) {  
  if (input > 10) {  
    //do sth  
    return;  
  }  
  // TODO
}2.2 三元運(yùn)算符
三元運(yùn)算符的使用可以簡(jiǎn)化某些if-else結(jié)構(gòu),使代碼更簡(jiǎn)潔易讀,如下示例:
public Integer calc(Integer input) {  
  if (input > 10) {  
    return 50;  
  } else {  
    return 100;  
  }  
}優(yōu)化后
public Integer calc(Integer input) {  
  return input>10 ? 50 : 100;  
}2.3 合并條件表達(dá)式
如果存在一系列返回相同結(jié)果的條件,可以將它們合并為單個(gè)條件表達(dá)式,從而使邏輯更清晰,如下示例:
public Integer calc(Player input) {  
  if(input.getAge() <18) {  
    return 5;  
  }  
  if (input.getHeight() < 1.80) {  
    return 5;  
  }  
  if (input.getWeight() < 50) {  
    return 5;  
  }  
  return 0;  
}優(yōu)化后
public Integer merge_conditional_expression_solution(Player input) {  
  if(input.getAge() <18 || input.getHeight() < 1.80 || input.getWeight() < 50) {  
    return 5;  
  }  
  return 0;  
}2.4 使用switch-case
switch-case 語(yǔ)句可用于處理多種條件,且代碼更簡(jiǎn)潔易讀,如下示例:
public Integer switch_example(Integer input) {  
  if (input == 1) {  
    //do sth 1  
  }  
  if(input == 2) {  
    //do sth 2  
  }  
  if(input ==3 ) {  
    //do sth 3  
  }  
  return 0;  
}優(yōu)化后
public Integer switch_solution(Integer input) {  
  switch (input) {  
    case 1: //do sth 1  
    case 2: //do sth 2  
    case 3: //do sth 3  
    default: return 0;  
  }  
}
// 或者如下
public Integer switch_solution(Integer input) {
  return switch (input) {
    case 1 -> {
      // do sth 1
      System.out.println("Handling case 1");
      yield 1; // 使用 yield 返回值
    }
    case 2 -> {
      // do sth 2
      System.out.println("Handling case 2");
      yield 2;
    }
    case 3 -> {
      // do sth 3
      System.out.println("Handling case 3");
      yield 3;
    }
    default -> {
      // default handling
      System.out.println("Default case");
      yield 0;
    }
  };
}2.5 守護(hù)函數(shù)
守護(hù)函數(shù)是一種用于保護(hù)其他函數(shù)免受無(wú)效輸入影響的函數(shù)。它通過(guò)檢查輸入的有效性,并在輸入無(wú)效時(shí)拋出異常來(lái)實(shí)現(xiàn)保護(hù)作用。簡(jiǎn)而言之,就是“盡早返回”,如下示例:
public Integer calc(Player input) {  
  if(input != null) {  
    String name = input.getName();  
    if(StringUtils.hasText(name)){  
      if(input.getAge() >18) {  
        return 60;  
      }  
    }  
  }  
}優(yōu)化后
public Integer calc(Player input) {  
  if(input == null) {  
    return 0;  
  }  
  if(!StringUtils.hasText(input.getName())){  
    return 0;  
  }  
  if(input.getAge() <=18) {  
    return 0;  
  }  
  return 60;  
}2.6 值的分配
當(dāng)你需要根據(jù)提供的某些輸入為變量分配新值時(shí),應(yīng)停止使用 if-else 語(yǔ)句,轉(zhuǎn)而采用更易讀的方式。如果我們不使用 else,代碼將變得更加簡(jiǎn)潔、清晰,如下示例:
public Integer calc(Integer input) {  
  if (input == 1) {  
    return 10;  
  } else if(input == 2) {  
    return 20;  
  } else {  
    return 0;  
  }  
}優(yōu)化后
public Integer value_assignment_solution(Integer input) {  
  if(input == 1) return 10;  
  if(input == 2) return 20;  
  return 0;  
}2.7 Optional
有時(shí)if-else更合適,因?yàn)樗鼤?huì)導(dǎo)致非空判斷,這種情況下可以使用Optional。如下示例:
public class OptionalWay {  
  public static void main(String[] args) {  
    OptionalWay optionalWay = new OptionalWay();  
    String s = "test";
    optionalWay.oldway(s);  
    optionalWay.newway(s);  
  }  
  private void errorHandle() {  
    log.error("exist a null");  
  }  
  private void keepWorking(String s) {  
    log.info(s);  
  }  
  // 優(yōu)化前
  private void oldway(String s) {  
    if(s != null) {  
      keepWorking(s);  
    } else {  
      errorHandle();  
    }  
  }  
  // 優(yōu)化后
  private void newway(String s) {  
    Optional<String> strOptional = Optional.of(s);  
    strOptional.ifPresentOrElse(this::keepWorking, this::errorHandle);  
  }  
}枚舉:在某些情況下,使用枚舉也能優(yōu)化if-else邏輯分支,如下示例:
public class EnumWay {
  public static void main(String[] args) {
    EnumWay enumWay = new EnumWay();
    enumWay.oldWay(18);
    enumWay.newWay(18);
  }
  // 優(yōu)化前
  private Integer oldWay(int i) {
    if(i==18){
      return 1;
    }else if(i == 20){
      return 2;
    }else if(i==30){
      return 3;
    }
    return 0;
  }
  // 優(yōu)化后
  private Integer newWay(int i) {
    return AgeValueEnum.of(i).getValue();
  }
  public enum AgeValueEnum {
    YOUND(18,1),
    MID(20,2),
    OLD(30,3);
    private int age;
    private int value;
    public int getAge() {
      return age;
    }
    public int getValue() {
      return value;
    }
    AgeValueEnum(int age, int value){
      this.age = age;
      this.value =value;
    }
    static AgeValueEnum of(int age) {
      for (AgeValueEnum temp : AgeValueEnum.values()) {
        if (temp.getAge() == age) {
          return temp;
        }
      }
      return null;
    }
  }
}2.8 反射機(jī)制
反射機(jī)制能夠獲取類和方法的信息,從而動(dòng)態(tài)執(zhí)行不同的代碼,如下示例:
public class Shape {
  public double getArea() {
    if (this instanceof Circle) {
      return Math.PI * ((Circle) this).getRadius() * ((Circle) this).getRadius();
    } else if (this instanceof Square) {
      return ((Square) this).getSide() * ((Square) this).getSide();
    } else if (this instanceof Triangle) {
      return 0.5 * ((Triangle) this).getBase() * ((Triangle) this).getHeight();
    } else {
      throw new IllegalArgumentException("Unknown shape type!");
    }
  }
}
public class Circle extends Shape {
  private double radius;
  // getters,setters,constructors
}
public class Square extends Shape {
  private double side;
}
public class Triangle extends Shape {
  private double base;
  private double height;
  // ...
}
public class Main {
  public static void main(String[] args) {
    Shape circle = new Circle(5);
    System.out.println("Circle area: " + circle.getArea());
    Shape square = new Square(4);
    System.out.println("Square area: " + square.getArea());
    Shape triangle = new Triangle(3, 4);
    System.out.println("Triangle area: " + triangle.getArea());
  }
}優(yōu)化后
public abstract class Shape {
    public abstract double getArea();
    public static Shape getShape(String shapeType) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class<?> clazz = Class.forName(shapeType);
        return (Shape) clazz.newInstance();
    }
}
public class Circle extends Shape {
  // ...
  @Override
  public double getArea() {
    return Math.PI * radius * radius;
  }
}
public class Square extends Shape {
  // ...
  @Override
  public double getArea() {
    return side * side;
  }
}
public class Triangle extends Shape {
  // ...
  @Override
  public double getArea() {
    return 0.5 * base * height;
  }
}
public class Main {
  public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    Shape circle = Shape.getShape("Circle");
    circle.setRadius(5);
    System.out.println("Circle area: " + circle.getArea());
    Shape square = Shape.getShape("Square");
    square.setSide(4);
    System.out.println("Square area: " + square.getArea());
    Shape triangle = Shape.getShape("Triangle");
    triangle.setBase(3);
    triangle.setHeight(4);
    System.out.println("Triangle area: " + triangle.getArea());
  }
}2.9 多態(tài)性
我們可以將某些操作(如不同狀態(tài))的通用方法抽象為一個(gè)公共接口,然后為這些操作實(shí)現(xiàn)該接口以完成不同的邏輯。在調(diào)用時(shí),只需傳入對(duì)應(yīng)的操作類實(shí)例,外部的調(diào)用方式保持一致,如下示例:
public class Animal {
  public void makeSound() {
    if (this instanceof Dog) {
      System.out.println("woof!");
    } else if (this instanceof Cat) {
      System.out.println("meow!");
    } else if (this instanceof Cow) {
      System.out.println("moo!");
    } else {
      System.out.println("UNKNOWN!");
    }
  }
}
public class Dog extends Animal {
}
public class Cat extends Animal {
}
public class Cow extends Animal {  
}
public class Main {
  public static void main(String[] args) {
    Animal dog = new Dog();
    dog.makeSound();
    Animal cat = new Cat();
    cat.makeSound();
    Animal cow = new Cow();
    cow.makeSound();
  }
}優(yōu)化后
// 動(dòng)物抽象類
public abstract class Animal {
  public abstract void makeSound();
}
// 狗類
public class Dog extends Animal {
  @Override
  public void makeSound() {
    System.out.println("woof!");
  }
}
// 貓類
public class Cat extends Animal {
  @Override
  public void makeSound() {
    System.out.println("meow!");
  }
}
// 牛類
public class Cow extends Animal {
  @Override
  public void makeSound() {
    System.out.println("moo!");
  }
}
// 主程序
public class Main {
  public static void main(String[] args) {
    Animal dog = new Dog();
    dog.makeSound();  // 輸出: woof!
    Animal cat = new Cat();
    cat.makeSound();  // 輸出: meow!
    Animal cow = new Cow();
    cow.makeSound();  // 輸出: moo!
  }
}2.10 策略模式
策略模式(Strategy Pattern)可以將不同的處理邏輯封裝到獨(dú)立的策略類中,從而避免使用冗長(zhǎng)的 if-else 或 switch-case 條件判斷代碼塊,如下示例:
public class StrategyMain {
  public static void main(String[] args) {
    oldway(18);
    newway(18);
  }
  private static void oldway(Integer age) {
    if(age.equals(18)) {
      //do sth young
    }else if(age.equals(20)){
      //do sth mid
    }else if(age.equals(30)){
      //do sth old
    }else {
      //do sth else
    }
  }
  private static void newway(Integer age) {
    IAgeService ageService = AgeServiceFactory.getAgeServiceImpl(age);
    ageService.value();
  }
}優(yōu)化后
public interface IAgeService {
  void value();
}
public class YoungAgeServiceImpl implements IAgeService {
  @Override
  public void value() {
    // do sth young
  }
}
public class MidAgeServiceImpl implements IAgeService {
  @Override
  public void value() {
    // do sth mid
  }
}
public class OldAgeServiceImpl implements IAgeService {
  @Override
  public void value() {
    // do sth old
  }
}
public class AgeServiceFactory {
  private static final Map<Integer, IAgeService> map = new HashMap<>();
  static {
    map.put(18, new YoungAgeServiceImpl());
    map.put(20, new MidAgeServiceImpl());
    map.put(30, new OldAgeServiceImpl());
  }
  public static IAgeService getAgeServiceImpl(Integer age) {
    return map.get(age);
  }
}2.11 責(zé)任鏈模式
責(zé)任鏈模式是一種重要的設(shè)計(jì)模式,它能有效減少 if-else 的使用,提高代碼的簡(jiǎn)潔性、可擴(kuò)展性和靈活性。當(dāng) if-else 中的條件表達(dá)式過(guò)于靈活,難以將條件中的數(shù)據(jù)抽象成表格并進(jìn)行統(tǒng)一判斷時(shí),就應(yīng)該將條件的判斷交給各個(gè)功能組件。這些組件以鏈?zhǔn)浇Y(jié)構(gòu)串聯(lián)起來(lái),形成一個(gè)完整的功能,如下示例:
public class FileHandler {
  public void handle(File file) {
    if (file instanceof TextFile) {
      System.out.println("Handle text file");
    } else if (file instanceof ImageFile) {
      System.out.println("Handle image file");
    } else if (file instanceof VideoFile) {
      System.out.println("Handle video file");
    } else {
      throw new IllegalArgumentException("Unknown file type!");
    }
  }
}
public class File {
  // 基類可以保持為空或添加通用文件屬性/方法
}
public class TextFile extends File {
}
public class ImageFile extends File {
}
public class VideoFile extends File {
}
// 添加UnknownFile類定義(假設(shè)這是另一個(gè)文件類型)
public class UnknownFile extends File {
}
public class Main {
  public static void main(String[] args) {
    FileHandler fileHandler = new FileHandler();
    TextFile textFile = new TextFile();
    fileHandler.handle(textFile);
    ImageFile imageFile = new ImageFile();
    fileHandler.handle(imageFile);
    VideoFile videoFile = new VideoFile();
    fileHandler.handle(videoFile);
    // 這會(huì)拋出IllegalArgumentException
    UnknownFile unknownFile = new UnknownFile(); 
    fileHandler.handle(unknownFile);
  }
}優(yōu)化后
public interface Handler {
  void handle(File file);
  void setNextHandler(Handler nextHandler);
}
public class TextFileHandler implements Handler {
  private Handler nextHandler;
  @Override
  public void handle(File file) {
    if (file instanceof TextFile) {
      System.out.println("Handle text file");
    } else if (nextHandler != null) {
      nextHandler.handle(file);
    }
  }
  @Override
  public void setNextHandler(Handler nextHandler) {
    this.nextHandler = nextHandler;
  }
}
public class ImageFileHandler implements Handler {
  private Handler nextHandler;
  @Override
  public void handle(File file) {
    if (file instanceof ImageFile) {
      System.out.println("Handle image file");
    } else if (nextHandler != null) {
      nextHandler.handle(file);
    }
  }
  @Override
  public void setNextHandler(Handler nextHandler) {
    this.nextHandler = nextHandler;
  }
}
public class VideoFileHandler implements Handler {
  private Handler nextHandler;
  @Override
  public void handle(File file) {
    if (file instanceof VideoFile) {
      System.out.println("Handle video file");
    } else if (nextHandler != null) {
      nextHandler.handle(file);
    }
  }
  @Override
  public void setNextHandler(Handler nextHandler) {
    this.nextHandler = nextHandler;
  }
}
// 添加默認(rèn)處理器處理未知文件類型
public class DefaultFileHandler implements Handler {
  @Override
  public void handle(File file) {
    System.out.println("Cannot handle this file type: " + file.getClass().getSimpleName());
  }
  @Override
  public void setNextHandler(Handler nextHandler) {
    // 末端處理器,不需要設(shè)置下一個(gè)處理器
  }
}
public class Main {
  public static void main(String[] args) {
    Handler textFileHandler = new TextFileHandler();
    Handler imageFileHandler = new ImageFileHandler();
    Handler videoFileHandler = new VideoFileHandler();
    Handler defaultFileHandler = new DefaultFileHandler(); // 新增默認(rèn)處理器
    textFileHandler.setNextHandler(imageFileHandler);
    imageFileHandler.setNextHandler(videoFileHandler);
    videoFileHandler.setNextHandler(defaultFileHandler); // 設(shè)置末端處理器
    TextFile textFile = new TextFile();
    textFileHandler.handle(textFile);
    ImageFile imageFile = new ImageFile();
    textFileHandler.handle(imageFile);
    VideoFile videoFile = new VideoFile();
    textFileHandler.handle(videoFile);
    UnknownFile unknownFile = new UnknownFile(); 
    textFileHandler.handle(unknownFile); // 現(xiàn)在會(huì)輸出無(wú)法處理的信息
  }
}2.12 表驅(qū)動(dòng)法
一種編程模式,其核心思想是將條件邏輯與處理邏輯分離,并將條件邏輯存儲(chǔ)在表格(或數(shù)據(jù)結(jié)構(gòu))中,從而避免使用大量的if-else或switch-case語(yǔ)句,如下示例:
public String doAction1(Player input) {  
  //do sth 1  
  return "sth 1";  
}  
public String doAction2(Player input) {  
  //do sth 2  
  return "sth 2";  
}  
public String doAction3(Player input) {  
  //do sth 3  
  return "sth 3";  
}
public void calc(Player input) {  
  Integer age = input.getAge();  
  if (age.equals(18)) {  
    doAction1(input);  
  } else if (age.equals(20)) {  
    doAction2(input);  
  } else if (age.equals(30)) {  
    doAction3(input);  
  }  
}優(yōu)化后:
public void calc(Player input) {  
  Map<Integer, Function> actionMappings = new HashMap<>();  
  actionMappings.put(18, (someParams) -> doAction1(input));  
  actionMappings.put(20, (someParams) -> doAction2(input));  
  actionMappings.put(30, (someParams) -> doAction3(input));  
  actionMappings.get(input.getAge()).apply(input);  
}














 
 
 









 
 
 
 