我正在尝试使用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());
}
}
}
答案 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
:
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());
请注意,如果s
与if
语句中的任何字符串不匹配,则不完全等效。
答案 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));
}
}