1

我正在尝试使用 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());
            }
        }
    }
4

8 回答 8

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 解决方案。我们配置地图而不是命令式/结构化决策,决策被抽象隐藏。

这在 Java 8 中与 : 配对时非常简洁enum

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);
于 2014-11-18T17:23:29.873 回答
3

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

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())));
于 2014-11-18T17:30:19.150 回答
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如果您使用s 代替Strings 或用其他人建议switchMap基于方法替换 s ,也可以使用此原则。但重要的是两步法,它允许您保持n输入单位到规范加上 m规范到输出单位的转换,而不是n输入单位乘以 m输出单位的转换。

于 2014-11-18T18:19:01.973 回答
1

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

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

请注意,如果与语句s中的任何字符串都不匹配,则它并不完全等效。if

于 2014-11-18T17:09:39.417 回答
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 解析为双精度然后只有一个 Converter 类,它将变得更具可读性。

于 2014-11-18T17:31:22.723 回答
0

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

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

但是,要真正使此代码更好,需要对其进行重构。

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

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

于 2014-11-18T17:28:39.507 回答
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     

 }
于 2014-11-18T17:33:25.650 回答
0

这样做

创建一个 InterfaceForConvertorTypes

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

然后实现转换器类型并将它们注册到注册集合中。只需一个 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));
        }
    }
于 2014-11-18T17:44:03.890 回答