前言
面试官问:代码中有大量的if-else应该如何优化?
接下来,我带你一步一步征服面试官!
觉得不错的同学可以加我公众号,会经常分享一些技术干货,以及热点AI和科技新闻
一、思路
首先我们要想,大量的if-else怎么会减少呢?其实就是要将一坨奥利给分散,变成一块块巧克力,那无非就是分散到不同类、不同方法、或者lambda表达式
我提供几种思路:
- 多态,将条件分支的处理逻辑封装在不同的子类中,并通过父类的引用来调用具体的子类对象。这样可以将 if-else 的条件判断转移到运行时的对象绑定过程中。
- 设计模式,策略模式、工厂模式、状态模式,这些设计模式可以将不同的条件分支逻辑封装到独立的类中,提高代码的可读性和可维护性。
- 使用函数式编程,使用函数式编程的特性如高阶函数、Lambda 表达式等来处理条件分支。函数式编程可以将条件判断转化为函数调用,简化代码逻辑,并提高代码的可读性。
- 重构代码,通过代码重构技术,将复杂的条件逻辑拆分成多个简单的方法或类,每个方法或类只处理特定的条件分支。这样可以提高代码的可读性和可维护性。
其实不管是那种思路,最后你都还是免不了要去匹配到某个类、某个方法、某个函数调用
二、实现
2.1 多态
假设您有一个系统,根据用户的角色来执行不同的操作。原始的 if-else 逻辑可能如下所示:
public class UserService {
public void performOperation(User user) {
if (user.getRole() == UserRole.ADMIN) {
// 管理员权限逻辑
} else if (user.getRole() == UserRole.USER) {
// 用户权限逻辑
} else if (user.getRole() == UserRole.GUEST) {
// 游客权限逻辑
}
}
}
现在,我们可以通过多态来优化这段代码。首先,定义一个抽象的角色类 UserRole,然后为每种角色创建具体的子类,并在每个子类中重写 performOperation 方法。
public abstract class UserRole {
public abstract void performOperation();
}
public class AdminRole extends UserRole {
@Override
public void performOperation() {
// 管理员权限逻辑
}
}
public class UserRole extends UserRole {
@Override
public void performOperation() {
// 用户权限逻辑
}
}
public class GuestRole extends UserRole {
@Override
public void performOperation() {
// 游客权限逻辑
}
}
现在,您的 UserService 可以根据不同的用户角色调用相应的 performOperation 方法,而不再需要复杂的 if-else 逻辑。
public class UserService {
public void performOperation(UserRole role) {
role.performOperation();
}
}
在调用处,您可以根据不同的用户角色创建相应的子类对象,然后传递给 UserService 来执行相应的操作。
public class Main {
public static void main(String[] args) {
UserRole userRole = new AdminRole(); // 或者其他角色
UserService userService = new UserService();
userService.performOperation(userRole);
}
}
2.2 设计模式
这里拿策略模式来举例说明:
假设您有一个计算器程序,根据用户选择的运算符执行不同的计算操作。原始的 if-else 逻辑可能如下所示:
public class Calculator {
public int calculate(int a, int b, String operator) {
if (operator.equals("+")) {
return a + b;
} else if (operator.equals("-")) {
return a - b;
} else if (operator.equals("*")) {
return a * b;
} else if (operator.equals("/")) {
return a / b;
}
throw new IllegalArgumentException("Invalid operator: " + operator);
}
}
现在,我们可以使用策略模式来重构代码。首先,定义一个接口 Operation,然后为每种运算符创建具体的实现类,并在每个实现类中重写 calculate 方法。
public interface Operation {
int calculate(int a, int b);
}
public class Addition implements Operation {
@Override
public int calculate(int a, int b) {
return a + b;
}
}
public class Subtraction implements Operation {
@Override
public int calculate(int a, int b) {
return a - b;
}
}
// 同样地,乘法和除法的实现类也可以类似地定义
然后,在 Calculator 类中引入 Operation 接口,并根据不同的运算符选择相应的实现类来执行计算。
public class Calculator {
private Operation operation;
public void setOperation(Operation operation) {
this.operation = operation;
}
public int calculate(int a, int b) {
return operation.calculate(a, b);
}
}
在调用处,您可以根据用户选择的运算符创建相应的实现类对象,并将其传递给 Calculator 来执行相应的计算操作。
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator();
calculator.setOperation(new Addition()); // 或者其他运算符的实现类
int result = calculator.calculate(10, 5);
System.out.println("Result: " + result);
}
}
通过使用策略模式,您可以将各种运算符的计算逻辑封装在单独的类中,并根据需要动态地选择不同的实现类来执行计算,从而避免了大量的 if-else 语句。
补充
还有一种特殊的 场景 可以使用责任链模式来优化,看下面的例子:
public void check(Integer status) {
if (status == 1) {
// balaba
status++;
check(status);
}
if (status == 2) {
// bababa
status++;
check(status);
}
if (status == 3) {
// lalal
status++;
check(status);
} else if ...
}
这种有固定执行顺序的就可以使用责任链模式
2.3 函数式编程
假设您有一个程序,根据用户输入的不同命令执行不同的操作。原始的 if-else 逻辑可能如下所示:
public class CommandHandler {
public void handle(String command) {
if ("start".equals(command)) {
start();
} else if ("stop".equals(command)) {
stop();
} else if ("restart".equals(command)) {
restart();
} else {
unknownCommand();
}
}
private void start() {
System.out.println("Starting...");
}
private void stop() {
System.out.println("Stopping...");
}
private void restart() {
System.out.println("Restarting...");
}
private void unknownCommand() {
System.out.println("Unknown command");
}
}
现在,我们可以使用函数式编程风格重构代码。首先,定义一个接口 Command,并在其中声明一个方法来执行命令,然后,我们可以为每个命令创建一个具体的实现类,并在其中实现相应的操作:
@FunctionalInterface
public interface Command {
void execute();
}
public class StartCommand implements Command {
@Override
public void execute() {
System.out.println("Starting...");
}
}
public class StopCommand implements Command {
@Override
public void execute() {
System.out.println("Stopping...");
}
}
public class RestartCommand implements Command {
@Override
public void execute() {
System.out.println("Restarting...");
}
}
在 CommandHandler 类中,我们可以使用一个 Map 来将命令名称映射到相应的命令对象,并根据用户输入执行相应的命令,在调用处,您只需创建一个 CommandHandler 对象,并调用其 handle 方法传入用户输入的命令即可:
import java.util.HashMap;
import java.util.Map;
public class CommandHandler {
private final Map<String, Command> commandMap = new HashMap<>();
public CommandHandler() {
commandMap.put("start", new StartCommand());
commandMap.put("stop", new StopCommand());
commandMap.put("restart", new RestartCommand());
}
public void handle(String command) {
Command cmd = commandMap.getOrDefault(command, () -> System.out.println("Unknown command"));
cmd.execute();
}
}
public class Main {
public static void main(String[] args) {
CommandHandler handler = new CommandHandler();
handler.handle("start"); // 或者其他命令
}
}
通过使用函数式编程风格,我们将各种命令的执行逻辑封装在单独的类中,并通过 lambda 表达式和函数式接口将命令与其操作关联起来,从而避免了大量的 if-else 语句。
三、优化
那么既然将代码拆分了,想要去匹配到正确的逻辑,要分情况考虑
3.1 简单条件
if (status == 1) {
// balaba
} else if (status == 2) {
// bababa
} else if (status == 3) {
// lalal
} else if ....
if (status == 1 && type == 'a') {
// balaba
} else if (status == 2 && type == 'b') {
// bababa
} else if (status == 3 && type == 'c') {
// lalal
} else if ....
可以看到,这种条件都是固定的参数和判断格式,此时我们可以使用map、数组等来优化,可以参考上面的函数式编程,将不同的实现或者函数提前放到一个map中,需要的时候直接get即可。
3.2 复杂条件
if (number > 1) {
if (number > 2) {
// bababa
} else if (number < 10) {
// lalal
}
} else if (number == 1) {
// bababa
} else {
if (number < -5) {
// lalal
} else if ....
}
if (status == 1 && type == 'a') {
// balaba
} else if (status == 2 || type == 'b') {
// bababa
} else if (status == 3 || type == 'c') {
// lalal
} else if ....
这种无法使用map和数组来实现,但是可以改变使用List,将不同的实现放到一个List中,然后使用for循环遍历接口实现类,接口定义一个方法专门来校验,返回boolean,如果是true就执行对应的方法。
总结
上述总结了常见场景下的一些优化思路,但是实际场景可能更加复杂,需要根据具体情况具体分析,有时候,可能不变更加合适。
希望大家工作顺利,成长飞速~~~