Refactoring-Imporving the Design of Exsiting Code — 代码的坏味道
发布日期:2025-05-02 04:47:37 浏览次数:15 分类:精选文章

本文共 7448 字,大约阅读时间需要 24 分钟。

代码的坏味道与重构优化

在软件开发过程中,代码的坏味道如重复代码、过长参数列、过长方法等问题会严重影响代码的可维护性和可扩展性。通过代码重构,我们可以有效地改善这些问题,使代码更清晰、更易于理解和维护。本文将详细探讨常见的代码坏味道及其重构方法。


1. 重复代码

重复代码主要分为三种类型:

  • 同一类内的重复代码:可以通过提炼方法将重复逻辑提取为一个独立的方法,并在原类中调用。
  • 不同类内的重复代码:可以将重复逻辑提炼到父类中,通过继承或组合方式实现代码复用。
  • 与其他类无关的重复代码:可以创建一个全新的类,将重复逻辑封装其中。

示例1

public class Car {
public void printBenz(String brand, String model, Integer price, double power) {
System.out.println("品牌" + brand);
System.out.println("型号:" + model);
System.out.println("动力:" + power);
System.out.println("价格:" + price);
double salePrice = price;
if (price > 200000) {
salePrice = price * 0.98;
}
if (power <= 1.6) {
System.out.println(salePrice * 0.05);
} else {
System.out.println(salePrice * 0.1);
}
}
public void printBmw(String brand, String model, Integer price, double power) {
System.out.println("品牌" + brand);
System.out.println("型号:" + model);
System.out.println("动力:" + power);
System.out.println("价格:" + price);
double salePrice = price;
if (price > 200000) {
salePrice = price * 0.98;
}
if (power <= 1.6) {
System.out.println(salePrice * 0.05);
} else {
System.out.println(salePrice * 0.1);
}
}
}

优化示例2

public class Car {
public void printBenz(String brand, String model, Integer price, double power) {
printBasicInfo(brand, model, price, power);
getTax(power, price);
}
public void printBmw(String brand, String model, Integer price, double power) {
printBasicInfo(brand, model, price, power);
getTax(power, price);
}
private void printBasicInfo(String brand, String model, Integer price, double power) {
System.out.println("品牌" + brand);
System.out.println("型号:" + model);
System.out.println("动力:" + power);
System.out.println("价格:" + price);
}
private double getTax(double power, Integer price) {
double salePrice = price;
if (price > 200000) {
salePrice = price * 0.98;
}
return (power <= 1.6) ? salePrice * 0.05 : salePrice * 0.1;
}
}

通过提炼printBasicInfogetTax方法,我们显著减少了重复代码,使代码结构更加清晰。


2. 过长参数列

长参数列会导致代码难以阅读和维护。可以通过引入参数对象将相关属性封装起来,从而减少参数数量。

示例3

public class Car {
public void printBenz(CarEntity carEntity) {
printBasicInfo(carEntity);
getTax(carEntity);
}
public void printBmw(CarEntity carEntity) {
printBasicInfo(carEntity);
getTax(carEntity);
}
private void printBasicInfo(CarEntity carEntity) {
System.out.println("品牌" + carEntity.getBrand());
System.out.println("型号:" + carEntity.getModel());
System.out.println("动力:" + carEntity.getPower());
System.out.println("价格:" + carEntity.getPrice());
}
private double getTax(CarEntity carEntity) {
double salePrice = carEntity.getPrice();
if (carEntity.getPrice() > 200000) {
salePrice = carEntity.getPrice() * 0.98;
}
return (carEntity.getPower() <= 1.6) ? salePrice * 0.05 : salePrice * 0.1;
}
}

通过引入CarEntity参数对象,我们将相关属性集中管理,降低了参数列的复杂度。


3. 过长方法

长方法通常伴随大量临时变量,导致代码难以理解。可以通过提炼临时变量和查询,将逻辑分解为更小的方法。

示例4

private double getTax(CarEntity carEntity) {
return getSalePrice(carEntity) * getTaxRate(carEntity);
}
private double getSalePrice(CarEntity carEntity) {
if (carEntity.getPrice() > 200000) {
return carEntity.getPrice() * 0.98;
}
return carEntity.getPrice();
}
private double getTaxRate(CarEntity carEntity) {
return (carEntity.getPower() <= 1.6) ? 0.05 : 0.1;
}

通过提炼getSalePricegetTaxRate,我们将复杂逻辑分解为更易于理解的方法。


4. 过大类

大类通常由多个不相关的功能组成,可以通过提炼子类将部分功能独立出来。

示例5

public abstract class BaseCar {
public abstract void printBasicInfo(CarEntity carEntity);
public abstract double getTax(CarEntity carEntity);
}
public class Benz extends BaseCar {
@Override
public void printBasicInfo(CarEntity carEntity) {
System.out.println("奔驰车信息");
}
@Override
public double getTax(CarEntity carEntity) {
// 具体税费计算逻辑
}
}
public class Bmw extends BaseCar {
@Override
public void printBasicInfo(CarEntity carEntity) {
System.out.println("宝马车信息");
}
@Override
public double getTax(CarEntity carEntity) {
// 具体税费计算逻辑
}
}

通过提炼BaseCar为抽象类,BenzBmw各自承担独立的业务逻辑。


5. 发散式变化

多个业务的修改集中在同一类中,导致类职责扩大。可以通过提炼子类将相关业务独立出来。

示例6

public class Product {
public double getPrice() {
// 原有计算价格逻辑
}
public int getStock() {
// 原有查询库存逻辑
}
}
// 提炼后
public class PriceCalculator {
public double getPrice(Product product) {
// 详细计算价格逻辑
}
}
public class StockManager {
public int getStock(Product product) {
// 详细查询库存逻辑
}
}

通过提炼PriceCalculatorStockManager,我们将价格和库存的业务分开管理。


6. 霰弹式修改

多处代码修改需要同时改动,导致维护成本高。可以通过提炼功能,将相关逻辑集中到一个类中。

示例7

public class Product {
public double getPrice() {
if (isPromotion) {
// 促销价格计算逻辑
} else if (isGroup) {
// 团购价格计算逻辑
} else {
// 正常价格计算逻辑
}
}
public int getStock() {
if (isPromotion) {
// 促销库存逻辑
} else if (isGroup) {
// 团购库存逻辑
} else {
// 正常库存逻辑
}
}
}

通过提炼Product为多个类,分别处理不同的业务逻辑,避免了霰弹式修改问题。


7. 依恋情结

一个类依赖另一个类的大量方法,导致代码难以维护。可以通过将依赖关系反转,提炼为独立的类。

示例8

public class Order {
private Person customer;
private Integer orderId;
public Order(Person customer, Integer orderId) {
this.customer = customer;
this.orderId = orderId;
}
public Person getCustomer() {
return customer;
}
public Integer getOrderId() {
return orderId;
}
public double calculateTotal() {
return customer.getAge() * this.orderId;
}
}

通过提炼Customer为独立类,Order类仅维护核心业务逻辑。


8. 基本型别偏执

过度使用基本类型会导致代码难以扩展。可以通过封装基本类型为对象来减少耦合。

示例9

public class Order {
private String username;
private String sex;
private Integer orderId;
private Integer price;
}

通过引入Customer类:

public class Customer {
private String username;
private String address;
}
public class Order {
private Customer customer;
private Integer orderId;
private Integer price;
}

通过封装usernameaddress,减少了基本类型的耦合。


9. 霰弹式修改

通过提炼方法,将多处代码集中到一个类中,避免了多处修改的问题。

示例10

public class Product {
public double getPrice(ProductType type) {
switch (type) {
case PROMOTION:
return calculatePromotionPrice();
case GROUP:
return calculateGroupPrice();
default:
return calculateNormalPrice();
}
}
public int getStock(ProductType type) {
switch (type) {
case PROMOTION:
return getPromotionStock();
case GROUP:
return getGroupStock();
default:
return getNormalStock();
}
}
private double calculatePromotionPrice() {
// 促销价格计算
}
private int getPromotionStock() {
// 促销库存计算
}
private double calculateGroupPrice() {
// 团购价格计算
}
private int getGroupStock() {
// 团购库存计算
}
private double calculateNormalPrice() {
// 正常价格计算
}
private int getNormalStock() {
// 正常库存计算
}
}

通过提炼Product为多个类,分别处理不同的业务逻辑,避免了霰弹式修改问题。


通过以上重构方法,我们可以有效改善代码的质量,使其更易于维护和扩展。

上一篇:PHP imap 远程命令执行漏洞复现(CVE-2018-19518)
下一篇:Referenced classpath provider does not exist: org.maven.ide.eclipse.launchconfig

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2026年05月31日 02时46分16秒