Java代码重构学习笔记-简化条件表达式

news/2024/11/29 8:52:26/

Decompose Conditional (分解条件表达式)

它的主要目的是将复杂的条件语句分解为多个简单的条件语句,从而提高代码的可读性和可维护性。

举个例子,假设有一个计费系统,其中包含一个 calculateFee 方法,负责根据用户的账单信息计算出用户的费用。最初的实现中,calculateFee 方法使用了一个复杂的 if-else 语句来判断不同的费用类型,并根据不同的条件进行计算,如下所示:

public double calculateFee(Bill bill) {double fee = 0;if (bill.getPlan() == PlanType.A) {if (bill.getUsage() > 100) {fee = 100 * bill.getBaseRate() + (bill.getUsage() - 100) * bill.getOverRate();} else {fee = bill.getUsage() * bill.getBaseRate();}} else if (bill.getPlan() == PlanType.B) {if (bill.getUsage() > 200) {fee = 200 * bill.getBaseRate() + (bill.getUsage() - 200) * bill.getOverRate();} else {fee = bill.getUsage() * bill.getBaseRate();}if (bill.getAccounts() > 1) {fee -= fee * 0.05;}}return fee;
}

这段代码使用了嵌套的 if-else 语句来判断不同的费用类型和不同的条件,并根据不同的条件进行计算。这样的代码很难阅读和理解,并且容易出现 bug。

为了解决这些问题,可以使用 “Decompose Conditional” 重构方法。具体实现方式是将嵌套的 if-else 语句分解为多个独立的语句,每个语句负责处理特定的条件。例如:

public double calculateFee(Bill bill) {double fee = 0;if (bill.getPlan() == PlanType.A) {fee = calculatePlanAFee(bill);} else if (bill.getPlan() == PlanType.B) {fee = calculatePlanBFee(bill);}return fee;
}private double calculatePlanAFee(Bill bill) {if (bill.getUsage() > 100) {return 100 * bill.getBaseRate() + (bill.getUsage() - 100) * bill.getOverRate();} else {return bill.getUsage() * bill.getBaseRate();}
}private double calculatePlanBFee(Bill bill) {double fee = 0;if (bill.getUsage() > 200) {fee = 200 * bill.getBaseRate() + (bill.getUsage() - 200) * bill.getOverRate();} else {fee = bill.getUsage() * bill.getBaseRate();}if (bill.getAccounts() > 1) {fee -= fee * 0.05;}return fee;
}

在上面的代码中,首先将嵌套的 if-else 语句分解为两个独立的语句,每个语句负责处理特定的条件。然后,将每个条件计算的代码封装到一个单独的方法中,以提高代码的可读性和可维护性。最后,在 calculateFee 方法中根据用户的费用类型调用不同的方法进行计算,并返回计算结果。

使用 “Decompose Conditional” 重构方法,可以将复杂的条件语句分解为多个简单的条件语句,从而提高代码的可读性和可维护性。

Consolidate Conditional Expression (合并条件表达式)

它的主要目的是将几个条件表达式合并为一个更简单的表达式。

举个例子,假设有一个计算商品折扣的方法 calculateDiscount,其中包含多个条件表达式来判断不同的折扣类型,如下所示:

public double calculateDiscount(double price, int quantity) {double discount = 0;if (price > 1000 && quantity > 10) {discount = price * 0.2;}if (price > 500 && quantity > 5) {discount = price * 0.1;}if (price > 100) {discount = price * 0.05;}return discount;
}

这段代码使用了多个条件表达式来判断不同的折扣类型,并根据不同的条件计算出折扣。如果有更多的折扣类型需要添加,那么这段代码会变得非常冗长和难以维护。

为了解决这些问题,可以使用 “Consolidate Conditional Expression” 重构方法。具体实现方式是将多个条件表达式合并为一个更简单的表达式。例如:

public double calculateDiscount(double price, int quantity) {double discount = 0;if (price > 1000 && quantity > 10) {discount = price * 0.2;} else if (price > 500 && quantity > 5) {discount = price * 0.1;} else if (price > 100) {discount = price * 0.05;}return discount;
}

在上面的代码中,将多个条件表达式合并为一个更简单的表达式,使用 else-if 语句进行处理。这样可以使代码更简洁、可读性更高,也更易于维护和扩展。

“Consolidate Conditional Expression” 是一种非常有用的重构方法,它能够将多个复杂的条件表达式合并为一个更简单的表达式,从而提高代码的可读性和可维护性。

Consolidate Duplicate Conditional Fragments (合并重复的条件片段)

它的主要目的是将重复的代码片段合并为一个更简单的形式。

举个例子,假设有一个方法 checkAge,用于检查用户的年龄是否符合要求。如果用户年龄小于 18 岁,那么该方法会返回 false,如果用户年龄大于等于 18 岁但小于 21 岁,那么该方法会弹出一个确认对话框,询问用户是否已经获得了父母或监护人的许可,如果用户确认获得了许可,则返回 true,否则返回 false。最后,如果用户年龄大于等于 21 岁,则直接返回 true。

原始实现中,checkAge 方法中包含了一些重复的代码,如下所示:

public boolean checkAge(int age) {if (age < 18) {return false;} else if (age >= 18 && age < 21) {boolean hasPermission = showPermissionDialog();if (hasPermission) {return true;} else {return false;}} else {return true;}
}private boolean showPermissionDialog() {// 弹出确认对话框,询问用户是否获得了父母或监护人的许可// 如果用户确认获得了许可,则返回 true,否则返回 false
}

在上面的代码中,checkAge 方法中包含了一些重复的代码。在第一个 if 分支和最后一个 else 分支中都只是返回了 true 或 false,这两个分支的代码是完全一样的。为了避免这种重复,可以使用 “Consolidate Duplicate Conditional Fragments” 重构方法,将这些重复的片段合并为一个更简洁的形式。

重构后的代码如下所示:

public boolean checkAge(int age) {boolean hasPermission = true;if (age >= 18 && age < 21) {// 弹出确认对话框,询问用户是否获得了父母或监护人的许可// 如果用户未确认获得了许可,则 hasPermission 设为 falsehasPermission = showPermissionDialog();}return age >= 18 || hasPermission;
}private boolean showPermissionDialog() {// 弹出确认对话框,询问用户是否获得了父母或监护人的许可// 如果用户确认获得了许可,则返回 true,否则返回 false
}

在上面的代码中,我们将重复的代码片段合并为了一个更简洁的形式。我们首先将变量 hasPermission 初始化为 true,然后在第二个条件分支中调用 showPermissionDialog 方法,根据用户的选择设置 hasPermission 的值,最后返回一个判断表达式,根据年龄和 hasPermission 来判断该用户是否符合要求。

通过使用 “Consolidate Duplicate Conditional Fragments” 重构方法,我们可以将重复的代码片段合并为一个更简洁的形式,提高代码的可读性和可维护性。

Remove Control Flag (移除控制标记)

它的主要目的是通过优化循环中的控制标记,来使代码更加清晰和易于理解。

举个例子,假设有一个方法 checkArray,用于检查数组中是否包含某个特定值。该方法使用了一个名为 found 的 boolean 变量,用于记录是否找到了该特定值。原始实现中,checkArray 方法使用了 for 循环来遍历数组,如果找到了该特定值,则将 found 设为 true,并跳出循环。

public boolean checkArray(int[] array, int value) {boolean found = false;for (int i = 0; i < array.length; i++) {if (array[i] == value) {found = true;break;}}return found;
}

在上面的代码中,使用了 found 变量来记录是否找到了该特定值。这种实现方式虽然可行,但是 found 变量仅仅被用来控制循环流程,而并未真正产生意义,从而降低了代码的可读性。

为了解决这些问题,可以使用 “Remove Control Flag” 重构方法。具体实现方式是使用 break 或 return 语句直接退出循环,而不是使用控制标记。例如:

public boolean checkArray(int[] array, int value) {for (int i = 0; i < array.length; i++) {if (array[i] == value) {return true;}}return false;
}

在上面的代码中,我们将控制标记 found 直接更改为使用返回值,如果找到了该特定值,则直接返回 true,否则返回 false。这种实现方式不仅减少了代码的复杂度,而且使代码更加简洁、清晰和易于理解。

通过使用 “Remove Control Flag” 重构方法,我们可以优化循环中的控制标记,使代码更加简洁、清晰和易于理解。同时,这种实现方式还可以提高代码的可读性和可维护性。

Replace Nested Conditional with Guard Clauses (以卫语句取代嵌套条件表达式)

它的主要目的是通过使用卫语句来取代嵌套条件表达式,从而使得代码更加清晰和易于理解。

举个例子,假设有一个方法 calculatePrice,用于计算某个商品的价格。该方法接收两个参数:basePrice,表示该商品的基本价格;season,表示当前季节。原始实现中,calculatePrice 方法使用了多个嵌套的条件语句来根据不同的季节计算商品的价格。具体实现如下:

public double calculatePrice(double basePrice, String season) {double price = 0.0;if (season.equals("春季")) {price = basePrice * 1.2;} else {if (season.equals("夏季")) {price = basePrice * 1.5;} else {if (season.equals("秋季")) {price = basePrice * 1.0;} else {if (season.equals("冬季")) {price = basePrice * 1.8;}}}}return price;
}

在上面的代码中,我们可以看到,使用了嵌套的 if-else 语句来判断不同的季节,并计算商品的价格。这种实现方式虽然可行,但是会使得代码变得复杂和难以理解。

为了解决这些问题,可以使用 “Replace Nested Conditional with Guard Clauses” 重构方法。具体实现方式是使用卫语句来避免嵌套条件表达式。例如:

public double calculatePrice(double basePrice, String season) {if (season.equals("春季")) {return basePrice * 1.2;}if (season.equals("夏季")) {return basePrice * 1.5;}if (season.equals("秋季")) {return basePrice * 1.0;}if (season.equals("冬季")) {return basePrice * 1.8;}return 0.0;
}

在上面的代码中,我们使用了多个卫语句来代替嵌套的条件表达式,如果当前季节匹配成功,则直接返回相应的价格,否则返回默认值 0.0。这种实现方式不仅使得代码更加简洁和易于理解,而且减少了代码的复杂度,提高了代码的可读性和可维护性。

通过使用 “Replace Nested Conditional with Guard Clauses” 重构方法,我们可以使用卫语句来取代嵌套条件表达式,使得代码更加简洁、清晰和易于理解。同时,这种实现方式还可以提高代码的可读性和可维护性,减少代码的复杂度。

Replace Conditional with Polymorphism (以多态取代条件表达式)

它的主要目的是通过使用多态来取代条件表达式,从而使得代码更加清晰和易于理解。

举个例子,假设有一个程序用于处理不同类型的几何图形,并计算它们的面积。该程序包含一个方法 calculateArea,用于计算某个几何图形的面积,该方法接收一个图形对象作为参数。原始实现中,calculateArea 方法使用了多个条件表达式来判断图形对象的类型,并根据不同的类型来计算面积。具体实现如下:

public double calculateArea(Shape shape) {if (shape instanceof Rectangle) {Rectangle rectangle = (Rectangle) shape;return rectangle.getWidth() * rectangle.getHeight();} else {if (shape instanceof Circle) {Circle circle = (Circle) shape;return Math.PI * circle.getRadius() * circle.getRadius();} else {throw new IllegalArgumentException("Unsupported shape type");}}
}

在上面的代码中,我们可以看到,使用了多个条件表达式来判断图形对象的类型,并根据不同的类型来计算面积。这种实现方式虽然可行,但是会使得代码变得复杂和难以维护。

为了解决这些问题,可以使用 “Replace Conditional with Polymorphism” 重构方法。具体实现方式是使用多态来避免条件表达式。例如:

public abstract class Shape {public abstract double calculateArea();
}public class Rectangle extends Shape {private double width;private double height;public Rectangle(double width, double height) {this.width = width;this.height = height;}@Overridepublic double calculateArea() {return width * height;}
}public class Circle extends Shape {private double radius;public Circle(double radius) {this.radius = radius;}@Overridepublic double calculateArea() {return Math.PI * radius * radius;}
}

在上面的代码中,我们定义了一个抽象类 Shape,并在其中定义了一个抽象方法 calculateArea,用于计算图形的面积。然后我们分别创建了两个子类 Rectangle 和 Circle,分别用于表示矩形和圆形,并实现了 calculateArea 方法。在客户端代码中,我们只需要传递一个具体的 Shape 对象,然后调用 calculateArea 方法即可计算出相应的面积。

通过使用 “Replace Conditional with Polymorphism” 重构方法,我们可以使用多态来取代条件表达式,使得代码更加简洁、清晰和易于理解。同时,这种实现方式还可以提高代码的可扩展性和可维护性,减少代码的复杂度,并避免了大量的类型判断和强制类型转换。

Introduce Null Object (引入 Null 对象)

它的主要目的是通过引入一个 “Null Object” 来取代空引用,从而使得代码更加健壮和易于维护。

举个例子,假设有一个程序用于处理文件系统中的文件,其中包含一个类 FileSystem,用于表示某个文件或目录。该类包含一个方法 getSize,用于计算文件或目录的大小。原始实现中,getSize 方法返回一个空引用(null),表示该文件或目录不存在。这样的实现方式虽然可行,但是容易导致空指针异常,需要在客户端代码中添加大量的判断语句来避免异常的发生。具体实现如下:

public class FileSystem {private String name;public FileSystem(String name) {this.name = name;}public long getSize() {// 模拟计算文件或目录的大小if (fileExists()) {return 100L;} else {return null; // 返回空引用(null)}}private boolean fileExists() {// 模拟判断文件或目录是否存在return false;}
}

在上面的代码中,我们可以看到,getSize 方法返回一个空引用(null),表示该文件或目录不存在。这种实现方式容易导致客户端代码出现空指针异常,需要在客户端代码中添加大量的判断语句来避免异常的发生。

为了解决这些问题,可以使用 “Introduce Null Object” 重构方法。具体实现方式是引入一个 “Null Object”,用于取代空引用。例如:

public interface FileSystem {long getSize();
}public class NullFileSystem implements FileSystem {public long getSize() {return 0L;}
}public class RealFileSystem implements FileSystem {private String name;public RealFileSystem(String name) {this.name = name;}public long getSize() {// 模拟计算文件或目录的大小if (fileExists()) {return 100L;} else {return 0L;}}private boolean fileExists() {// 模拟判断文件或目录是否存在return false;}
}

在上面的代码中,我们定义了一个接口 FileSystem,并在其中定义了一个 getSize 方法,用于计算文件或目录的大小。然后我们分别创建了两个实现类 NullFileSystem 和 RealFileSystem,分别用于表示空对象和真实对象,并实现了 getSize 方法。在客户端代码中,我们只需要传递一个具体的 FileSystem 对象,然后调用 getSize 方法即可计算出相应的大小。

通过使用 “Introduce Null Object” 重构方法,我们可以引入一个 “Null Object” 来取代空引用,使得代码更加健壮和易于维护。同时,这种实现方式还能够提高代码的可扩展性和可维护性,减少客户端代码的复杂度,并避免了空指针异常的发生。

Introduce Assertion (引入断言)

它的主要目的是在代码中添加断言,用于检查程序的正确性和稳定性。

举个例子,假设有一个程序用于处理银行账户,并包含一个类 BankAccount,用于表示某个用户的账户信息。该类包含一个方法 deposit,用于存款。原始实现中,deposit 方法只是简单地将存款金额加到当前余额上,没有进行任何检查和验证。这样的实现方式容易导致存款后余额为负数,需要在客户端代码中添加大量的判断语句来避免异常的发生。具体实现如下:

public class BankAccount {private double balance;public void deposit(double amount) {balance += amount; // 存款}public double getBalance() {return balance;}
}

在上面的代码中,我们可以看到,deposit 方法只是简单地将存款金额加到当前余额上,没有进行任何检查和验证。这种实现方式容易导致存款后余额为负数,需要在客户端代码中添加大量的判断语句来避免异常的发生。

为了解决这些问题,可以使用 “Introduce Assertion” 重构方法。具体实现方式是在代码中添加断言,用于检查程序的正确性和稳定性。例如:

public class BankAccount {private double balance;public void deposit(double amount) {assert amount > 0; // 断言存款金额必须大于零balance += amount; // 存款assert balance >= 0; // 断言存款后余额必须大于等于零}public double getBalance() {return balance;}
}

在上面的代码中,我们使用两个断言来检查存款金额和存款后余额是否符合要求。如果不符合要求,则会抛出 AssertionError 异常。在客户端代码中,我们可以根据需要启用或禁用断言。

通过使用 “Introduce Assertion” 重构方法,我们可以在代码中添加断言,用于检查程序的正确性和稳定性。这种实现方式能够提高代码的可靠性和稳定性,并减少客户端代码的复杂度。同时,这种实现方式也能够提供更好的调试和测试支持。


http://www.ppmy.cn/news/64856.html

相关文章

影像已成为小米手机向上的强劲动力

4月18日&#xff0c;小米正式发布13 Ultra。 这款新机一亮相&#xff0c;就以全球亮度最高的屏幕、以及出类拔萃的徕卡Summicron镜头征服了用户。 一、火爆的小米13 Ultra 这次发布会上&#xff0c;小米13 Ultra是与小米电视大师 86" Mini LED、小米平板6、小米手环8、…

ResearchRabbit.ai: 学术论文摘要研究工具

【产品介绍】 ResearchRabbit是一个帮助研究人员发现、跟踪和分享学术论文的平台。可以根据你的兴趣和收藏提供个性化的推荐和摘要&#xff0c;并且可以让你可视化论文和作者之间的网络关系。 Researchrabbit.ai是一个基于人工智能的文献搜索和管理工具&#xff0c;它可以帮助你…

qemu-基础篇——程序编译过程(四)

文章目录 程序编译过程声明GCC 常用工具链GCCBinutilsC 运行库 ENV编译过程预处理编译汇编链接 分析 ELF 文件ELF 文件的段反汇编 ELF 程序编译过程 计算机程序设计语言通常分为机器语言、汇编语言和高级语言三类。高级语言需要通过翻译成机器语言才能执行&#xff0c;而翻译的…

Dtop环球嘉年华全球Web3.0分布式私域电商生态发展峰会圆满举办

5月7日,Dtop环球嘉年华全球Web3.0分布式跨境私域电商生态发展峰会暨战略合作备忘录签署仪式在马来西亚首都吉隆坡隆重举办。此次峰会汇集了Dtop环球嘉年华韩国、新加坡、澳洲、泰国、印尼等国家的社区联合发起人,环球自治商学院地区代表及来自Dtop环球嘉年华不同国家的粉丝用户…

JMeter压力测试案例(商品超卖并发问题)

什么要对接口压测呢? 压力测试可以用来验证软件系统的稳定性和可靠性&#xff0c;在压力下测试系统的性能和稳定性&#xff0c;发现并解决潜在的问题&#xff0c;确保系统在高负载情况下不会崩溃。压力测试可以用来评估软件系统的容量和性能&#xff0c;通过模拟高负载情况下…

微信小程序开发19__第三方UI组件Vant Weapp的应用

为了提高小程序的开发效率&#xff0c; 可以考虑使用第三方 UI 组件来实现界面的视觉统一。 本文以有赞第三方 UI 组件库 Vant Weapp 为例&#xff0c;介绍如何使用自定义组件 实现一个小程序。 Vant Weapp 是一款轻量、 可靠的小程序UI组件库&#xff0c; 与有赞移动端组…

AndroidStudio如何进行手机应用开发?

文章目录 0.引言1.AndroidStudio开发环境配置2.创建第一个手机应用 0.引言 Android手机应用因其搭载于手机&#xff0c;使用便捷&#xff0c;应用被大量开发使用。笔者使用手机多年&#xff0c;用过许多手机软件&#xff0c;在使用的过程中&#xff0c;虽然手机软件能解决大部分…

c++ static修饰类的成员

静态成员就是成员变量和成员函数前面加上static,称为静态成员 1.static修饰成员变量 (1)所有对象共享static成员变量&#xff0c;一旦一个对象数据对其进行改动&#xff0c;所有对象调用其数据也会改变&#xff0c;一改全改。 (2)编译阶段分配内存&#xff0c;static成员变量…