16+种优雅重构if-else块的方法
===================
16+种优雅重构if-else块的方法
===================
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