1. 首页
  2. 后端

16+种优雅重构if-else块的方法

  16+种优雅重构if-else块的方法

===================

16+种优雅重构if-else块的方法

===================

if-else是我们日常开发中非常常见的代码结构,但它经常被错误或不恰当地使用。这篇文章将详细解释如何优雅而正确地重构。

6+种优雅重构if-else块的方法"

让我们直接深入代码:

删除不必要的else

你经常会发现else块实际上根本不需要。

//before
public void remove_unnecessary_else_example(Integer input) {  
    if (input > 10) {  
        //do sth  
    } else {  
        //do sth else  
    }  
}  


//after  
public void remove_unnecessary_else_solution(Integer input) {  
    if (input > 10) {  
        //do sth  
        return;  
    }  

    //do sth else  
}

三元运算符

使用三元运算符可以简化一些if-else,使代码更加简洁易读。

//before
public Integer the_ternary_operator_example(Integer input) {  
    if (input > 10) {  
        return 50;  
    } else {  
        return 100;  
    }  
}  

//after  
public Integer the_ternary_operator_solution(Integer input) {  
    return input>10 ? 50 : 100;  
}

合并条件表达式

如果有一系列返回相同结果的条件,则可以将它们联合收割机组合成单个条件表达式,以使逻辑更清晰

//before
public Integer merge_conditional_expression_example(Player input) {  
    if(input.getAge() <18) {  
        return 5;  
    }  

    if (input.getHeight() < 1.80) {  
        return 5;  
    }  

    if (input.getWeight() < 50) {  
        return 5;  
    }  

    //do sth  
    return 0;  
}  

//after
public Integer merge_conditional_expression_solution(Player input) {  
    if(input.getAge() <18 || input.getHeight() < 1.80 || input.getWeight() < 50) {  
        return 5;  
    }  

    //do sth  
    return 0;  
}

switch-case:最常见的方式

switch-case语句可用于处理多个条件,代码更加简洁易读

//before
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;  
}  

//after
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;  
    }  
}

保护功能

保护函数是用于保护其他函数免受无效输入影响的函数。它通过检查输入的有效性并在输入无效时抛出异常来实现这一点。一句话,“尽快return”。

//before
public Integer guard_function_example(Player input) {  
    if(input != null) {  
        String name = input.getName();  
        if(StringUtils.hasText(name)){  
            if(input.getAge() >18) {  
                return 60;  
            }  
        }  
    }  
}  

//after
public Integer guard_function_solution(Player input) {  
    if(input == null) {  
        return 0;  
    }  

    if(!StringUtils.hasText(input.getName())){  
        return 0;  
    }  

    if(input.getAge() <=18) {  
        return 0;  
    }  
    return 60;  
}

值分布

如果你根据提供的一些输入给一个变量赋一个新值,停止使用if-else,并采取一种更可读的方法。

如果我们不使用else,我们将得到干净、可读的代码。

//before
public Integer value_assignment_example(Integer input) {  
    if (input == 1) {  
        return 10;  
    } else if(input == 2) {  
        return 20;  
    } else {  
        return 0;  
    }  
}  

//after
public Integer value_assignment_solution(Integer input) {  
    if(input == 1) return 10;  
    if(input == 2) return 20;  
    return 0;  
}

Optional

有时候if-else比较多,是因为非空判断造成的,这种情况下可以使用Optional

@Slf4j  
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);  
    }  

    //before
    private void oldway(String s) {  
        if(s != null) {  
            keepWorking(s);  
        } else {  
            errorHandle();  
        }  
    }  

    //after
    private void newway(String s) {  
        Optional strOptional = Optional.of(s);  
        strOptional.ifPresentOrElse(this::keepWorking, this::errorHandle);  
    }  

}

枚举:

在某些情况下,使用枚举还可以优化if-else逻辑分支

public class EnumWay {  

    public static void main(String[] args) {  
        EnumWay enumWay = new EnumWay();  

        enumWay.oldWay(18);  
        enumWay.newWay(18);  
    }  


    //before  
    private Integer oldWay(int i) {  
        if(i==18){  
            return 1;  
        }else if(i == 20){  
            return 2;  
        }else if(i==30){  
            return 3;  
        }  
        return 0;  
    }  



    //after
    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;  
        }  
    }  
}

中间

反射机制

反射机制可以获取有关类和方法的信息,以动态执行不同的代码。

//before
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;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }
}

public class Square extends Shape {

    private double side;

    public Square(double side) {
        this.side = side;
    }

    public double getSide() {
        return side;
    }
}

public class Triangle extends Shape {

    private double base;
    private double height;

    public Triangle(double base, double height) {
        this.base = base;
        this.height = height;
    }

    public double getBase() {
        return base;
    }

    public double getHeight() {
        return 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());
    }
}




//after
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 {

    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

public class Square extends Shape {

    private double side;

    public Square(double side) {
        this.side = side;
    }

    public double getSide() {
        return side;
    }

    @Override
    public double getArea() {
        return side * side;
    }
}

public class Triangle extends Shape {

    private double base;
    private double height;

    public Triangle(double base, double height) {
        this.base = base;
        this.height = height;
    }

    public double getBase() {
        return base;
    }

    public double getHeight() {
        return height;
    }

    @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());
    }
}

多态性

我们可以把一些操作(比如一些状态)的一些常用方法抽象成一个公共接口,然后实现这些接口为这些操作完成不同的逻辑,在调用时我们只需要传递相应的操作类,对外的操作方法是一样的。

//before
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();
    }

}


//after


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();

        Animal cat = new Cat();
        cat.makeSound();

        Animal cow = new Cow();
        bird.makeSound();
    }
}

策略模式

策略模式可以将不同的处理逻辑封装到不同的策略类中,从而避免使用多个if else代码块

//before
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();  
    }  
}

//after
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 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);  
    }  
}

责任链模式

责任链模式是一种重要的设计模式,它可以有效地减少if-else的使用,提高代码的简单性、可扩展性和灵活性。

当if-else中的条件表达式过于灵活,无法将条件中的数据抽象到一个表中,并以统一的方式进行判断时,则应将条件的判断交给各个功能组件。这些部件以链条的形式串联起来,形成一个完整的功能。

//before
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 TextFile extends File {

}

public class ImageFile extends File {

}

public class VideoFile 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);

        UnknownFile unknownFile = new UnknownFile(); 
        fileHandler.handle(unknownFile);
    }
}


//after
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 {

    @Override
    public void handle(File file) {
        if (file instanceof VideoFile) {
            System.out.println("Handle video file");
        }
    }
}

public class Main {

    public static void main(String[] args) {
        Handler textFileHandler = new TextFileHandler();
        Handler imageFileHandler = new ImageFileHandler();
        Handler videoFileHandler = new VideoFileHandler();

        textFileHandler.setNextHandler(imageFileHandler);
        imageFileHandler.setNextHandler(videoFileHandler);

        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);
    }
}

表驱动法

一种编程模式,它基本上将条件逻辑与处理逻辑分开,并将条件逻辑存储在表中,从而避免使用大量的if-else语句。

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";  
}

//before
public void table_driven_example(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);  
    }  
}


//after
public void table_driven_solution(Player input) {  
    Map 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);  
}

先进

对于某些需要动态处理的复杂业务流程场景,可以考虑以下高级方法。由于这些方法需要与特定的业务和框架相结合,因此本文将不演示这些方法的代码。如果你有兴趣,可以参考我以前的一些文章:

事件驱动

通过将不同的事件类型与相应的处理机制相关联,可以实现复杂的逻辑并实现解耦。

实现方法:Guava / Spring /消息队列。

您可以参考这篇文章以进一步了解:

Spring应用程序事件机制

规则引擎

规则引擎允许您定义和动态执行规则,通过安排条件来处理业务逻辑。它适用于处理复杂的业务逻辑。

推荐框架:Drools、mvel、LiteFlow.

有限状态机

状态机也可以看作是一种表驱动的方法。它是当前状态和事件与处理函数之间的映射。当然,在处理成功之后,也会有一个状态转换处理。

适用场景:状态机在协议栈、订单处理等功能上具有天然优势。这是因为这些场景自然具有状态和状态流。

您可以参考这篇文章以进一步了解:

Spring State Machine 4.0如何帮助我们?

原文链接: https://juejin.cn/post/7381784676721000487

文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17033.html

QR code