博客
关于我
Refactoring-Imporving the Design of Exsiting Code — 代码的坏味道
阅读量:795 次
发布时间:2023-02-27

本文共 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为多个类,分别处理不同的业务逻辑,避免了霰弹式修改问题。


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

转载地址:http://ievfk.baihongyu.com/

你可能感兴趣的文章
Oracle修改字段类型
查看>>
oracle典型安装失败,安装oracle 10失败
查看>>
Oracle分析函数之LEAD和LAG
查看>>
Oracle和SQL server的数据类型比较
查看>>
Oracle用游标删除重复数据
查看>>
Oracle监听配置、数据库实例配置等
查看>>
Oracle系列:安装Oracle RAC数据库(二)
查看>>
oracle系统 介绍,ORACLE数据库管理系统介绍
查看>>
oracle获取数据库表、字段、注释、约束等
查看>>
Oracle计划将ZGC项目提交给OpenJDK
查看>>
Oracle闪回技术(Flashback)
查看>>
oracle零碎要点---ip地址问题,服务问题,系统默认密码问题
查看>>
oracle零碎要点---oracle em的web访问地址忘了
查看>>
Oracle零碎要点---多表联合查询,收集数据库基本资料
查看>>
Oracle静默安装
查看>>
Oracle面试题:Oracle中truncate和delete的区别
查看>>
ThreadLocal线程内部存储类
查看>>
thinkphp 常用SQL执行语句总结
查看>>
Oracle:ORA-00911: 无效字符
查看>>
Text-to-Image with Diffusion models的巅峰之作:深入解读 DALL·E 2
查看>>