本文共 7448 字,大约阅读时间需要 24 分钟。
在软件开发过程中,代码的坏味道如重复代码、过长参数列、过长方法等问题会严重影响代码的可维护性和可扩展性。通过代码重构,我们可以有效地改善这些问题,使代码更清晰、更易于理解和维护。本文将详细探讨常见的代码坏味道及其重构方法。
重复代码主要分为三种类型:
示例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; }} 通过提炼printBasicInfo和getTax方法,我们显著减少了重复代码,使代码结构更加清晰。
长参数列会导致代码难以阅读和维护。可以通过引入参数对象将相关属性封装起来,从而减少参数数量。
示例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参数对象,我们将相关属性集中管理,降低了参数列的复杂度。
长方法通常伴随大量临时变量,导致代码难以理解。可以通过提炼临时变量和查询,将逻辑分解为更小的方法。
示例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;} 通过提炼getSalePrice和getTaxRate,我们将复杂逻辑分解为更易于理解的方法。
大类通常由多个不相关的功能组成,可以通过提炼子类将部分功能独立出来。
示例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为抽象类,Benz和Bmw各自承担独立的业务逻辑。
多个业务的修改集中在同一类中,导致类职责扩大。可以通过提炼子类将相关业务独立出来。
示例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) { // 详细查询库存逻辑 }} 通过提炼PriceCalculator和StockManager,我们将价格和库存的业务分开管理。
多处代码修改需要同时改动,导致维护成本高。可以通过提炼功能,将相关逻辑集中到一个类中。
示例7:
public class Product { public double getPrice() { if (isPromotion) { // 促销价格计算逻辑 } else if (isGroup) { // 团购价格计算逻辑 } else { // 正常价格计算逻辑 } } public int getStock() { if (isPromotion) { // 促销库存逻辑 } else if (isGroup) { // 团购库存逻辑 } else { // 正常库存逻辑 } }} 通过提炼Product为多个类,分别处理不同的业务逻辑,避免了霰弹式修改问题。
一个类依赖另一个类的大量方法,导致代码难以维护。可以通过将依赖关系反转,提炼为独立的类。
示例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类仅维护核心业务逻辑。
过度使用基本类型会导致代码难以扩展。可以通过封装基本类型为对象来减少耦合。
示例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;} 通过封装username和address,减少了基本类型的耦合。
通过提炼方法,将多处代码集中到一个类中,避免了多处修改的问题。
示例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/