减少IF语句java

时间:2014-11-18 17:05:18

标签: java if-statement scenebuilder reducing

我正在尝试使用javafx创建一个单位转换器 - 我已经搜索了两天我如何减少这些if语句。不知何故,我发现了一些类似的问题,但由于我是Java的新手,所以它对我没有帮助 - 我不知道我的情况是否正确。

希望你们能帮助我 -

谢谢

/**
     * CELSIUS TO
     */
    Celsius celsius = new Celsius(parseInput);
        if(cbOne.getValue().equals("Celsius")) {
            if(cbTwo.getValue().equals("Celsius") ) {
                showAnswer.setText(celsius.celsiusToCelsius());
            }
            if(cbTwo.getValue().equals("Fahrenheit")) {
                showAnswer.setText(celsius.celsiusToFahrenheit());
            }
            if(cbTwo.getValue().equals("Kelvin")) {
                showAnswer.setText(celsius.celsiusToKelvin());
            }
        }
    /**
     * FAHRENHEIT TO
     */
    Fahrenheit fahr = new Fahrenheit(parseInput);
        if(cbOne.getValue().equals("Fahrenheit") ) {
            if(cbTwo.getValue().equals("Celsius") ) {
                showAnswer.setText(fahr.fahrenheitToCelsius());
            }
            if(cbTwo.getValue().equals("Fahrenheit")) {
                showAnswer.setText(fahr.fahrenheitToFahrenheit());
            }
            if(cbTwo.getValue().equals("Kelvin")) {
                showAnswer.setText(fahr.fahrenheitToKelvin());
            }
        }
    /**
     * KELVIN TO
     */
    Kelvin kelvin = new Kelvin(parseInput);
        if(cbOne.getValue().equals("Kelvin")) {
            if(cbTwo.getValue().equals("Celsius") ) {
                showAnswer.setText(kelvin.kelvinToCelsius());
            }
            if(cbTwo.getValue().equals("Fahrenheit")) {
                showAnswer.setText(kelvin.kelvinToFahrenheit());
            }
            if(cbTwo.getValue().equals("Kelvin")) {
                showAnswer.setText(kelvin.kelvinToKelvin());
            }
        }
    }

8 个答案:

答案 0 :(得分:4)

实际上你的if语句适用于小程序。他们非常清楚。但是,您可以通过检查cbOne.getValue().equals(cbTwo.getValue())来减少冗余。这会将3个if语句换成1。

如果您有很多这些,您将受益于地图和界面方案。

interface Converter {
    double convert(double from);
}

static final Map<String, Map<String, Converter>> converters = (
    new HashMap<String, Map<String, Converter>>()
);
static {
    Map<String, Converter> fromCelsius = new HashMap<String, Converter>();

    fromCelsius.put(   "Celsius", new NoConversionConverter()       );
    fromCelsius.put("Fahrenheit", new CelsiusToFahrenheitConverter());
    fromCelsius.put(    "Kelvin", new CelsiusToKelvinConverter()    );

    converters.put("Celsius", fromCelsius);

    ...
}

static Converter getConverter(String from, String to) {
    Map<String, Converter> fromMap = converters.get(from);
    return fromMap == null ? null : fromMap.get(to);
}

Map是常见的OOP解决方案。我们不是通过命令式/结构化决策来配置Map,而是通过抽象来隐藏决策。

enum

配对时,这在Java 8中非常简洁
public enum Scale {
    CELSIUS, FAHRENHEIT, KELVIN;
    private final Map<Scale, DoubleUnaryOperator> ops = new HashMap<>();

    public DoubleUnaryOperator to(Scale to) {
        return to == this ? DoubleUnaryOperator.identity() : ops.get(to);
    }

    static {
        put(    CELSIUS, FAHRENHEIT, c -> c * 9.0 / 5.0 + 32.0     );
        put(    CELSIUS,     KELVIN, c -> c + 273.15               );
        put( FAHRENHEIT,    CELSIUS, f -> (f - 32.0) * 5.0 / 9.0   );
        put( FAHRENHEIT,     KELVIN, f -> (f + 459.67) * 5.0 / 9.0 );
        put(     KELVIN, FAHRENHEIT, k -> k * 9.0 / 5.0 + 459.67   );
        put(     KELVIN,    CELSIUS, k -> k - 273.15               );
    }

    private static void put(Scale from, Scale to, DoubleUnaryOperator op) {
        from.ops.put(to, op);
    }
}

也非常易读:

Scale      source = Scale.valueOf("CELSIUS");
Scale destination = Scale.valueOf("FAHRENHEIT");
double     result = source.to(destination).applyAsDouble(0.0);

答案 1 :(得分:3)

您不需要3个类来表示不同比例的温度。创建一个始终在内部保持Kelvins温度的类,并将其转换为任何其他比例的输出。有这样的课程:

public final class Temperature {
  public enum Scale {
    Celsius, Fahrenheit, Kelvin
  }

  private final double temperature;

  private Temperature(double temperature) {
    this.temperature = temperature;
  }

  public static Temperature create(double temperature, Scale scale) {
    switch (scale) {
      case Celsius:
        return new Temperature(temperature + 273.15);
      case Fahrenheit:
        return new Temperature((temperature + 459.67) * 5.0 / 9.0);
      case Kelvin:
        return new Temperature(temperature);
      default:
        throw new IllegalArgumentException("Unknown scale");
    }
  }

  public double convertTo(Scale scale) {
    switch (scale) {
      case Celsius:
        return temperature - 273.15;
      case Fahrenheit:
        return temperature * 9.0 / 5.0 - 459.67;
      case Kelvin:
        return temperature;
      default:
        throw new IllegalArgumentException("Unknown scale");
    }
  }
}

您的代码变为:

Temperature temp = Temperature.create(parseInput, Scale.valueOf(cbOne.getValue()));
showAnswer.setText(temp.convertTo(Scale.valueOf(cbTwo.getValue())));

答案 2 :(得分:2)

你最大的问题是你创造了一个n×m问题应该是n + m问题。

要解决这个问题,首先要定义一个规范单位,然后将问题分解为两个步骤,从源单位转换为规范单位,然后从规范单位转换为目标单位。

例如,如果将开尔文定义为规范单位,则代码可能类似于:

switch(inputUnit.getValue())
{
  case "Fahrenheit": kelvin=fahrenheitToKelvin(input); break;
  case "Celsius":    kelvin=celsiusToKelvin(input); break;
  case "Kelvin":     kelvin=input; break;
  default: throw new AssertionError();
}
switch(outputUnit.getValue())
{
  case "Fahrenheit": output=kelvinToFahrenheit(kelvin); break;
  case "Celsius":    output=kelvinToCelsius(kelvin); break;
  case "Kelvin":     output=kelvin; break;
  default: throw new AssertionError();
}
showAnswer.setText(output);

我省略字符串到数字和数字到字符串转换,因为很明显这些转换只需要在选择器之外执行一次。

如果您使用enum代替String s或使用其他人建议的基于switch的方法替换Map,也可以使用此原则。但重要的是两步法允许您将n输入单元维护为规范 m规范输出单位转换而不是n输入单位 m输出单位转换次数。

答案 3 :(得分:1)

由于您不必稍后使用更多单位修改此代码,我建议您使用三元运算符:

String s = cbTwo.getValue();
showAnswer.setText(s.equals("Celsius") ? fahr.fahrenheitToCelsius() :
    s.equals("Farenheit") ? fahr.fahrenheitToFahrenheit() : kelvin.kelvinToKelvin()); 

请注意,如果sif语句中的任何字符串不匹配,则不完全等效。

答案 4 :(得分:1)

您可以将任何输入值转换为开尔文,然后从开尔文转换为所需的结果:

String unit = cbOne.getValue();
double inputInKelvin;
String outUnit = cbTwo.getValue();

// parse
if ( unit.equals("Celsius") ) inputInKelvin = new Celsius(parseInput).celsiusToKelvin();
else if ( unit.equals("Fahrenheit") ) inputInKelvin = new Fahrenheit(parseInput).fahrenheitToKelvin();
else inputInKelvin = new Kelvin(parseInput).kelvinToKelvin();

// output
Kelvin kelvin = new Kelvin(inputInKelvin);
if ( unit.equals("Celsius") ) showAnswer.setText(kelvin.kelvinToCelsius());
else if ( unit.equals("Fahrenheit") ) showAnswer.setText(kelvin.kelvinToFahrenheit());
else showAnswer.setText( kelvin.kelvinToKelvin() );

如果先将String解析为double,然后只有一个Converter类,那么它将更具可读性。

答案 5 :(得分:0)

虽然三元运算符可以工作,但很难阅读和维护。

稍微好一点可能是第一个if语句中的switch语句。但是,您编写的代码是完全可以理解的,不需要从这个角度进行更改。

但是,要真正使代码更好,需要重新考虑。

编写的代码有两个棘手的特征。首先,只使用一个温度对象时,实例化所有温度对象。

其次,UI和业务逻辑耦合得过于紧密。如果更改UI元素的名称,则必须更改业务逻辑。此外,如果您为应用程序添加其他方式来转换温度,您将无法重复使用此代码。

答案 6 :(得分:0)

您也可以这样做:

 final int CELSIUS = 1,FARANHITE = 2,KELVIN = 3;

然后像这样使用switch语句

 int key = StringToInt(firstValue)*10 + StringTOInt(secondValue);
 //This will give you 9 unique codes 11 12 13 21 22 23 ....
 switch(key)
 {
       default: case 11: case 22: case 33: break;
       //do nothing since no conversion required

       case 12://Celsius to faranhite
       case 13://celsius to kelvin
       .
       .
       //and so on     

 }

答案 7 :(得分:0)

这样做

创建InterfaceForConvertorTypes

public interface Convertor {
    public String convert(int parseInt);
    public boolean accept(String from, String to);
}

然后实现转换器类型并在registery集合中注册它们。 只需一个IF就可以达到你想要的效果。

List<Convertor> convertors = new ArrayList<Convertor>();

    Convertor CelsiusToCelsius = new Convertor() {

        @Override
        public String convert(int parseInt) {
            Celsius celsius = new Celsius(parseInt);
            return celsius.celsiusToCelsius();
        }

        @Override
        public boolean accept(String from, String to) {
            return from.equals("Celsius") && to.equals("Celsius");
        }
    };


    Convertor CelsiusToFah = new Convertor() {

        @Override
        public String convert(int parseInt) {
            Celsius celsius = new Celsius(parseInt);
            return celsius.celsiusToFahrenheit();
        }

        @Override
        public boolean accept(String from, String to) {
            return from.equals("Celsius") && to.equals("Fahrenheit");
        }
    };

    Convertor CelsiusToKelvin = new Convertor() {

        @Override
        public String convert(int parseInt) {
            Celsius celsius = new Celsius(parseInt);
            return celsius.celsiusToFahrenheit();
        }

        @Override
        public boolean accept(String from, String to) {
            return from.equals("Celsius") && to.equals("Kelvin");
        }
    };

   // create Rest of Convertor like above

    convertors.add(CelsiusToFah);
    convertors.add(CelsiusToCelsius);
    convertors.add(CelsiusToKelvin);
    // register rest of convertor


    //Thats it!
    for(Convertor convertor:convertors) {
        if(convertor.accept(cbOne.getValue(), cbTwo.getValue())) {
            showAnswer.setText(convertor.convert(parseInput));
        }
    }