With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.
Fahrenheit Celsius Kelvin
+----------+-------+-------+
Fahrenheit| | | |
+----------+-------+-------+
Celsius | | | |
+----------+-------+-------+
Kelvin | | | |
+----------+-------+-------+
public double getValueAs(T targetUnits) {
// TEMPERATURE MEASUREMENT *******************************************
if (this.measurementUnits.getClass() == TemperatureUnits.class) {
if (targetUnits == TemperatureUnits.FAHRENHEIT) {
if (this.measurementUnits == TemperatureUnits.FAHRENHEIT) {
return this.value;
}
else if (this.measurementUnits == TemperatureUnits.CELSIUS) {
return convertCelsiusToFahrenheit(this.value);
}
else if (this.measurementUnits == TemperatureUnits.KELVIN) {
return convertKelvinToFahrenheit(this.value);
}
else {
//can not convert
}
}
else if (targetUnits == TemperatureUnits.CELSIUS) {
if (this.measurementUnits == TemperatureUnits.FAHRENHEIT) {
return convertFahrenheitToCelsius(this.value);
}
else if (this.measurementUnits == TemperatureUnits.CELSIUS) {
return this.value;
}
else if (this.measurementUnits == TemperatureUnits.KELVIN) {
return convertKelvinToCelsius(this.value);
}
else {
//can not convert
}
}
else if (targetUnits == TemperatureUnits.KELVIN) {
if (this.measurementUnits == TemperatureUnits.FAHRENHEIT) {
return convertFahrenheitToKelvin(this.value);
}
else if (this.measurementUnits == TemperatureUnits.CELSIUS) {
return convertCelsiusToKelvin(this.value);
}
else if (this.measurementUnits == TemperatureUnits.KELVIN) {
return value;
}
else {
//can not convert
}
}
else {
//can not convert
}
}
// LENGTH MEASUREMENT *******************************************
else if (this.unitType == LengthUnits.class) {
if (targetUnits == LengthUnits.INCHES) {
if (this.measurementUnits == LengthUnits.INCHES) {
return this.value;
}
else if (this.measurementUnits == LengthUnits.FEET) {
return convertFeetToInches(this.value);
}
else if (this.measurementUnits == LengthUnits.MILES) {
return convertMilesToInches(this.value);
}
else {
//can not convert
}
}
else if (targetUnits == LengthUnits.FEET) {
if (this.measurementUnits == LengthUnits.INCHES) {
return convertInchesToFeet(this.value);
}
else if (this.measurementUnits == LengthUnits.FEET) {
return value;
}
else if (this.measurementUnits == LengthUnits.MILES) {
return convertMilesToFeet(this.value);
}
else {
//can not convert
}
}
else if (targetUnits == LengthUnits.MILES) {
if (this.measurementUnits == LengthUnits.INCHES) {
return convertInchesToMiles(this.value);
}
else if (this.measurementUnits == LengthUnits.FEET) {
return convertFeetToMiles(this.value);
}
else if (this.measurementUnits == LengthUnits.MILES) {
return value;
}
else {
//can not convert
}
}
else {
//can not convert
}
}
return 0;
}
My first attempt was to try Polymorphism and Strategy Pattern, but I realized that was just spreading out the if-else statements so they were all over the place, rather than reducing them or eliminating them. public double getValueAs(T targetUnits) {
if (this.measurementUnits.getClass() == TemperatureUnits.class) {
return TemperatureConverter.convert((TemperatureUnits) this.measurementUnits, (TemperatureUnits) targetUnits, this.value);
}
(plus I haven't actually tested the targetUnits to see if I can cast them to TemperatureUnits. I'll have to throw in a test for that if casting is the way to go.)Oh yes that is a good idea. I has the same idea and noticed JScience did the same thing: convert to a base unit, then from there convert to targetUnit.
Is there a way to extract some of this conversion code into it's own class without using a cast?
public class Measurement<T extends Units> {
private Class<T> unitType;
private T measurementUnits;
private double value;
public Measurement(T u, double v) {
this.value = v;
this.measurementUnits = u;
this.unitType = u.getClass(); // CAN'T DO THIS
T[] x = u.values(); // CAN'T DO THIS
}
So I'm switching back to my original idea of generating massive amounts of nearly identical code using a Code Template and a simple code generating program which replaces "MeasurementType" with "Temperature" or "Length" or whatever...
The problem is that your basic approach is quadratic in the number of units. You have 3 possible inputs and 3 possible outputs, so there are 9 cells (3x3) in your matrix. But if you expand this to 6 units, you get 36 cells in your matrix, each of which needs the correct code (the correct Callable). It's the sort of design that leads to problems - because it's easy to get it right for 33 of those 36 and wrong for the last 3 and then that's very hard to find. (Why does converting to Farenheit work from Kelvin, but not from Celsius? etc.)
What I'd propose instead is reducing the complexity to a linear relationship with your number of units. You can do that by mapping from an arbitrary input unit to one standard unit and then from that standard unit back to an arbitrary unit. That way if you have 6 units, there are 6 mappings to the standard and then 6 back. Which is linear rather than quadratic, so much easier to test and get right.
Let me make that a bit more concrete with some code...which I hope you can see is simpler, because each method is pretty short and easy to understand. Also if you wish to add a new set of units, the places to put the new conversion are pretty obvious.
Any good?
Doug
Open in new window