patternjavaMinor
Unit converter application
Viewed 0 times
converterunitapplication
Problem
I am working on an Android unit converter application, but I came to the point where I have to assign the formulas to the calculation method. At the moment I am using a switch-case statement, as it is more neat than an if-else, but still this proves to be very, very lengthy.
The way the application works is the user selects type of unit to convert, e.g. length. Then 2 spinners show up, one for the "From" unit and one for the "To" unit. On calculation the code picks up what is chosen in the spinners and determines the right formula to use.
Here is a code snippet for only one unit conversion:
This will become so, so long after just few units being written down, so I was wondering if there's a better way of doing things. I am open to all sort of changes.
The way the application works is the user selects type of unit to convert, e.g. length. Then 2 spinners show up, one for the "From" unit and one for the "To" unit. On calculation the code picks up what is chosen in the spinners and determines the right formula to use.
Here is a code snippet for only one unit conversion:
switch (unitFrom) {
case "Kilometers": switch (unitTo){
case "Miles": initialValue = (initialValue / 1.6);
break;
case "Metres": initialValue *= 1000;
break;
case "Centimetres": initialValue *= 100000;
break;
case "Millimetres": initialValue *= 1000000;
break;
case "Feet": initialValue *= 3280.8399;
break;
case "Yards": initialValue *= 1093.6133;
break;
case "Inches": initialValue *= 39370.0787;
break;
case "Nautical Miles": initialValue *= 0.539956803;
break;
case "Fathoms": initialValue *= 546.806649;
break;
case "Light Years": initialValue *= (1.05702341*(10^-13));
break;
}
}This will become so, so long after just few units being written down, so I was wondering if there's a better way of doing things. I am open to all sort of changes.
Solution
The problem with code like this is that it grows very quickly.
Adding one unit means that you have to provide conversions to every other unit. But there's a pattern in your code:
Each unit is essentially just a factor. And the conversion is just the multiplication of the length value with that factor.
Take a look at the SI unit system, where such factors are actually part of the unit:
"milli" which would generally be considered part of the unit is actually just a number with a name:
Notice that the opposite conversion means to divide by that factor.
To simplify the conversion, you can choose a common base unit.
Now you don't have to convert every unit to every other unit but only have to specify one conversion: to/from the base unit.
Here's an example class doing this:
The program does every conversion possible.
I kept the conversion from one unit to itself in as a quick test. If you don't want that, opt-out when
Additional thoughts:
The name of each unit is only specified once. Retyping string literals is prone to error
You could go further and define a class
switch (unitFrom) {
case "Kilometers": switch (unitTo){Adding one unit means that you have to provide conversions to every other unit. But there's a pattern in your code:
case "Metres": initialValue *= 1000;
break;
case "Centimetres": initialValue *= 100000;
break;
case "Millimetres": initialValue *= 1000000;
break;
case "Feet": initialValue *= 3280.8399;
break;
case "Yards": initialValue *= 1093.6133;
break;
case "Inches": initialValue *= 39370.0787;Each unit is essentially just a factor. And the conversion is just the multiplication of the length value with that factor.
Take a look at the SI unit system, where such factors are actually part of the unit:
1 mm = =1 millimeter = 1 * milli * meter = 1 * 10^(-3) * meter"milli" which would generally be considered part of the unit is actually just a number with a name:
10^(-3)Notice that the opposite conversion means to divide by that factor.
To simplify the conversion, you can choose a common base unit.
Now you don't have to convert every unit to every other unit but only have to specify one conversion: to/from the base unit.
Here's an example class doing this:
import java.util.HashMap;
import java.util.Set;
public class Converter
{
public static void main (String[] args)
{
Converter converter = new Converter();
Set units = converter.availableUnits();
double value = 5.4;
for (String unitFrom : units)
{
System.out.println(value + " " + unitFrom + " are:");
for (String unitTo : units)
{
System.out.println("\t" + converter.convert(unitFrom, unitTo, value) + " " + unitTo);
}
System.out.println();
}
}
private HashMap _units;
public Converter()
{
_units = new HashMap();
_units.put("Millimetres", 1.0);
_units.put("Metres", 1000.0);
_units.put("Inches", 25.4);
_units.put("Feet", 304.8);
_units.put("Yards", 914.4);
}
public double convert(String from, String to, double value)
{
return value * _units.get(from) / _units.get(to);
}
private Set availableUnits()
{
return _units.keySet();
}
}The program does every conversion possible.
I kept the conversion from one unit to itself in as a quick test. If you don't want that, opt-out when
unitFrom == unitTo.5.4 Millimetres are:
5.4 Millimetres
0.017716535433070866 Feet
0.21259842519685043 Inches
0.0054 Metres
0.005905511811023623 Yards
5.4 Feet are:
1645.92 Millimetres
5.4 Feet
64.80000000000001 Inches
1.64592 Metres
1.8 Yards
5.4 Inches are:
137.16 Millimetres
0.44999999999999996 Feet
5.4 Inches
0.13716 Metres
0.15 Yards
5.4 Metres are:
5400.0 Millimetres
17.716535433070867 Feet
212.5984251968504 Inches
5.4 Metres
5.905511811023622 Yards
5.4 Yards are:
4937.76 Millimetres
16.2 Feet
194.4 Inches
4.93776 Metres
5.4 YardsAdditional thoughts:
The name of each unit is only specified once. Retyping string literals is prone to error
"Millimetres" != "Millimeters", which the compiler cannot catch.You could go further and define a class
Unit, which besides the name and factor can contain, an abbreviation, plural and singular forms, etc.Code Snippets
switch (unitFrom) {
case "Kilometers": switch (unitTo){case "Metres": initialValue *= 1000;
break;
case "Centimetres": initialValue *= 100000;
break;
case "Millimetres": initialValue *= 1000000;
break;
case "Feet": initialValue *= 3280.8399;
break;
case "Yards": initialValue *= 1093.6133;
break;
case "Inches": initialValue *= 39370.0787;1 mm = =1 millimeter = 1 * milli * meter = 1 * 10^(-3) * meterimport java.util.HashMap;
import java.util.Set;
public class Converter
{
public static void main (String[] args)
{
Converter converter = new Converter();
Set<String> units = converter.availableUnits();
double value = 5.4;
for (String unitFrom : units)
{
System.out.println(value + " " + unitFrom + " are:");
for (String unitTo : units)
{
System.out.println("\t" + converter.convert(unitFrom, unitTo, value) + " " + unitTo);
}
System.out.println();
}
}
private HashMap<String, Double> _units;
public Converter()
{
_units = new HashMap<String, Double>();
_units.put("Millimetres", 1.0);
_units.put("Metres", 1000.0);
_units.put("Inches", 25.4);
_units.put("Feet", 304.8);
_units.put("Yards", 914.4);
}
public double convert(String from, String to, double value)
{
return value * _units.get(from) / _units.get(to);
}
private Set<String> availableUnits()
{
return _units.keySet();
}
}5.4 Millimetres are:
5.4 Millimetres
0.017716535433070866 Feet
0.21259842519685043 Inches
0.0054 Metres
0.005905511811023623 Yards
5.4 Feet are:
1645.92 Millimetres
5.4 Feet
64.80000000000001 Inches
1.64592 Metres
1.8 Yards
5.4 Inches are:
137.16 Millimetres
0.44999999999999996 Feet
5.4 Inches
0.13716 Metres
0.15 Yards
5.4 Metres are:
5400.0 Millimetres
17.716535433070867 Feet
212.5984251968504 Inches
5.4 Metres
5.905511811023622 Yards
5.4 Yards are:
4937.76 Millimetres
16.2 Feet
194.4 Inches
4.93776 Metres
5.4 YardsContext
StackExchange Code Review Q#119894, answer score: 3
Revisions (0)
No revisions yet.