【问题标题】:How to refactor to reduce complexity of this code?如何重构以降低此代码的复杂性?
【发布时间】:2021-02-04 16:52:23
【问题描述】:

我有以下代码,我需要对其进行重构以降低复杂性并增加模块化和封装性。我还需要降低 ck 指标值。

    private void initialiseVehicle(String vehicleName) {
        if(vehicleName.equals("Boat")) {
            vehicle = new Boat("Apollo ");
        }
        else if(vehicleName.equals("Ship")) {
            vehicle = new Ship("Cruizz");
        }
        else if(vehicleName.equals("Truck")) {
            vehicle = new Truck("Ford F-650");
        }
        else if(vehicleName.equals("Motorcycle")) {
            vehicle = new Motorcycle("Suzuki");
        }
        else if(vehicleName.equals("Bus")) {
            vehicle = new Bus("Aero");
        }
        else if(vehicleName.equals("Car")) {
            vehicle = new Car("BMW");
        }
        else if(vehicleName.equals("Bicycle")) {
            vehicle = new Bicycle("A-bike");
        }
        else if(vehicleName.equals("Helicopter")) {
            vehicle = new Helicopter("Eurocopter");
        }
        else if(vehicleName.equals("Airplane")) {
            vehicle = new Airplane("BA");
        }
        else if(vehicleName.equals("Tram")) {
            vehicle = new Tram("EdinburghTram");
        }
        else if(vehicleName.equals("Train")) {
            vehicle = new Train("Virgin",4);
        }       
    }

你如何重构这段代码? switch-cases 是否降低了复杂性?

【问题讨论】:

  • switch 不会这样做,但您可以创建一个 Map<String, Vehicle> 并更改您的代码以使用 map.get(vehicleName)
  • 你能从代码中取一行举个例子吗?
  • 您能否详细说明我如何使用 Map map = new HashMap();通过展示一个例子来解决这个问题?谢谢@VLAZ
  • @VLAZ 当然地图是首选方式,但为什么开关不起作用?
  • @VLAZ 这也让我感到惊讶!一个开关会使指标值上升很多点。

标签: java refactoring cyclomatic-complexity


【解决方案1】:

一个选项可能如下所示:

Map<String, Function<String, Vehicle>> constructors = new HashMap<>();
constructors.put("Boat", name -> new Boat(name));
constructors.put("Ship", name -> new Ship(name));

那么 if/else 代码可能看起来像

Function<String, Vehicle> constructor = constructors.get(vehicleName);
Vehicle vehicle = constructor.apply("Apollo");

【讨论】:

  • Map map = new HashMap();这可以用来解决问题吗?任何其他方法都非常受欢迎。我还需要另一种方法来重构我的代码。再次感谢@Erik
  • 很好地使用 lambdas。
  • 我不确定Map&lt;String, String[]&gt; 在这里是否有用,但我缺乏一些上下文。在您的代码中,所有Boats 都将被命名为“Apollo”,所有Cars 都将被命名为“BMW”,这是没有意义的。这些名称应该是硬编码的吗?
  • 如此接近,但为什么你让所有对象都接收字符串"Apollo"作为构造函数参数?这不是问题中的代码正在做的事情。使用Supplier&lt;Vehicle&gt;,以及() -&gt; new Boat("Apollo ")() -&gt; new Train("Virgin", 4) 等lambda。
  • 感谢@Calculuswhiz!你能举一个从代码中取一行的例子吗?
【解决方案2】:

使用反射:

Vehicle vehicle;

Map<String,String> m = new HashMap<>() {{
    put("Boat", "Apollo");
    put("Ship", "Cruizz");
    // etc
}};
private void initializeVehicle(String name) throws Exception {
    vehicle = (Vehicle) Class.forName(name)
                             .getConstructor(String.class)
                             .newInstance(m.get(name));
}

但是老实说,我认为您的原始代码很简单。圈复杂度本身不应成为目标。

这段代码在 CK 中可能得分很低,但它不像 if/else 链那么容易理解。

所以,考虑一下你打算用它做什么,上面的例子对于不知道要创建的类的库非常有用。

这是完整的运行示例

import java.util.*;
import java.lang.reflect.*;
import static java.lang.System.out;

class Vehicle {
    String name;

    public Vehicle(String aName) {
        name = aName;
    }
}

class Boat extends Vehicle {
    public Boat(String s) {
        super(s);
    }
}

class Ship extends Vehicle {
    public Ship(String s) {
        super(s);
    }
}

class Main {
    Vehicle vehicle;

    Map<String,String> m = new HashMap<>() {{
        put("Boat", "Apollo");
        put("Ship", "Cruizz");
        // etc
    }};
    private void initializeVehicle(String name) throws Exception {
        vehicle = (Vehicle) Class.forName(name).getConstructor(String.class).newInstance(m.get(name));
    }

    public static void main(String... args) throws Exception {
      Main main = new Main();
      main.initializeVehicle("Ship");
      System.out.println(main.vehicle.name); // prints Cruizz as expected 
      
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-19
    • 2022-12-06
    • 1970-01-01
    • 2021-10-31
    相关资源
    最近更新 更多