0

All you need to remember is that diving by x is the same as multiplying by 1/x
So every conversion can be done as a multiplication, you just define the factor appropriately.
eg meters to yards, multiply by 1.09361

Another hint:
When designing a class, and especially a "model" class like this, don't start with its code. Start by thinking about how you want to use this class. Jot down some examples of the method calls you would ideally like to make use of this class. That gives you the method signatures for the public methods of your class. Now start coding.
That's why I posted examples of using my converter class, rather than posting any of its internal code. Looking at the code you posted I can't see how I would use those methods to convert between two units.

Edited by JamesCherrill

0

Right, so I tried to do what you suggested and this is how I did it.
You said to think about the methods that use that class.
So, first of all a constructor, which will initialize the conversion:

public ConverterModel(double unitToConvert){        
        this.unitToConvert = unitToConvert;
    }

unitToConvert should contain a double which is the number to convert. This eventually will come from user input
I'm not initializing the multipliers because I thought those will be constants, something like:

private final double KM_TO_MILES = 0.62137; //multiplication
private final double MILES_TO_KM = 1.6; //multiplication
private final double METRES_TO_YARDS =  0.9144; //division

Anyway, back to the methods.
A setter and getter for unitToConvert.

I will then need to do the actual conversion.
The signature method should be something like this
private void doConversion(double unitToConvert);
so it takes only the unit to convert
Now, I need a way to work out which constant to use, and the only way I'm thinking to do that is to make some checks inside the conversion method, like, if unit is KM then use KM_TO_MILES etc, perhaps a switch statement
Also, I think I wasn't clear on the multiplication vs division earlier on. What I meant was, even if I can multiply by the conversion constant or multiply by 1/conversion constant, I still need a mechanism to determine which one I need to do one or the other

0

I still need a mechanism to determine which one I need to do one or the other

No. When you supply the conversion constant simply use the value that's approriate for multiplication.

private final double METRES_TO_YARDS =  1.09361; // multiplication

I need a way to work out which constant to use

Maybe a switch, but a Map<which unit, conversion factor> scales and maintains better.
Or go O.O. and have a Unit class with one instance for each unit containing the unit name, conversion factor (etc). That's by far the most powerful but in th end, the easiest way. Remember degrees C/F need more than just a multiplier. Have another look at the code I posted last which shows how easy it is the set up a converter with a UnitDefinition class.

Edited by JamesCherrill

0

OK, so I had a look at the UnitDefinition, but I'm not sure how that works. I looked for some tutorial but I couldn't find any, strangely I couldn't even find it in the Java API. I was looking for it so I could read how that works etc, I mean, if you say that's the easiest way then I'm happy to try

0

It's a little class I wrote. I didn't post the code because I wanted you to see WHY it's defined the way it is. Anyway, here it is now...

class UnitDefinition { // immutable class, so can use public members

    // defines one unit in terms of an implicit or explicit base unit
    // unit value = base value * multipier + offset

    public final String name;
    public final double multiplier; // relative to "base" unit
    public final double offset;     // relative to "base" unit

    public UnitDefinition(String name) {
        // this is an explicit "base" unit that all others are converted to/from
        this.name = name;
        this.multiplier = 1;
        this.offset = 0;
    }

    public UnitDefinition(String name, double multiplier) {
        // for units with no offset (length, weight etc)
        this.name = name;
        this.multiplier = multiplier;
        this.offset = 0;
    }

    public UnitDefinition(String name, double multiplier, double offset) {
        // eg Farenheit (C as base unti): ("F",5.0/9,32)
        this.name = name;
        this.multiplier = multiplier;
        this.offset = offset;
    }

    // these conversion methods could be overidden in a subclass if there is 
    // a unit conversion that cannot be expressed as a multiplier and offset.
    // eg ratio to dB uses a log conversion

    public double convertToBase(double value) {
        return (value - offset) * multiplier;
    }

    public double convertFromBase(double value) {
        return value / multiplier + offset;
    }

}

Think about that, and I'll post the Converter class that uses those definitons later.
J

Edited by JamesCherrill

0

Part 2:

This is a little sketch of how the unit definitions are used for a conversion. Rather than having n^2 methods that convert directly between any two units, we have 2*n methods that convert via a "base" unit. Eg All lengths are defined in terms of the Meter, so that's our base unit for lengths. Instead of converting kilometers -> miles we convert kM-> Meters, then Meters -> Miles. For just two units it doesn't gain you much, but if you have cm, meters, km, inches, feet, yards, and miles it's a HUGE simplification.

The actual Conversion class is a lot more interesting, but this is the basic principle behind it:

// a kilometer is 1000 meters
UnitDefinition kM = new UnitDefinition("kM", 1000);
// similarly...
UnitDefinition mile = new UnitDefinition("Mile", 1609.34);
UnitDefinition yard = new UnitDefinition("Yard", 0.9144);

// convert kM to miles or yards...
double kMs = ...... whatever

double baseValue = kM.convertToBase(kMs);

double miles = mile.convertFromBase(baseValue);
double yards = yard.convertFromBase(baseValue);
0

OK thanks, sorry I didn't realize that was your own class.
I think the benefits of this approach will become obvious to me later on, and I also think I will have a lot of questions to ask, some perhaps you might think will be silly.

So, let me pause for a second and think about what to do.
To start with you're saying to have a class similar to your UnitDefinition that represent the conversion and that therefore does all the conversion using the base reference "metres": in this class no matter what conversion you want to do, everything gets converted first to metres and then to the unit you want to convert to, like yards to metres to km. What if I want to convert to metres instead?
Then create another class to test that class. But how do I get that to work with a GUI interface, like radio buttons? Or shouldn't I worry about that as yet?

0

There are no silly questions.

Conversion to meters (which happens tp be the base unit) is the same as any other conversion - just add Meters to your definitions

UnitDefinition Meter = new UnitDefinition("M"); // default multiplier = 1

and carry on - technically its ever so slightly inefficient, but it's more important to keep your code simple.

Of course, if you re converting a different kind of unit (ounces, pounds, kilograms, etc) them there will be a different base unit (kg in that case). That means you can't convert from (eg) yards to pounds - but that's true anyway.

Yes, don't worry about the GUI yet. If you can perform the desired conversions from a test class then you can perform them from a GUI. I said the Conversion class is more interesting, and setting up ypur radio buttons is part of that. But one step at a time.

Edited by JamesCherrill

0

Right, so in my test class (MyUI) I have the object creation. For now, I only create KM and metres:

UnitDef Meters = new UnitDef("M");//base value constructor
        UnitDef kM = new UnitDef("kM",1000);//KM conversion
        /*UnitDef mile = new UnitDef("Mile", 1609.34);
        UnitDef yard = new UnitDef("yards", 0.9144);*/

        double kMs = 5.0;
        double baseValue = kM.convertToBaseValue(kMs);
        /*double miles = mile.convertFromBaseValue(baseValue);
        double yards = yard.convertFromBaseValue(baseValue);*/

And then the UnitDef

public class UnitDef extends CustomComponent{
    public  String name;
    public  double multiplier;
    public UnitDef(String name){//base unit
        this.name = name;
        this.multiplier = 1;
    }
    public UnitDef(String name, double multiplier){//overloaded constructor taking name and multiplier depending on conversion
        this.name = name;
        this.multiplier = multiplier;
    }
    public double convertToBaseValue(double value){
        value = value / multiplier;
        System.out.println("convertToBaseValue() and value is " + value);
        return value;

    }
    public double convertFromBaseValue(double value){
        value = value * multiplier;
        System.out.println("convertFromBaseValue() and value is " + value);
        return value;

    }
}

Now,this is supposed to test only KM. I assigned a value of 5 to km, but the conversion to base is obviously off, as it gives me 0,005 rather than 5000, so should I define KM as 1/5 instead?

0

I think it's more natural to define the unit like you did ( 1kM = 1000M), so it's better to swap the multiplies and divides in your two convert methods - ie multiply when converting units to base, divide when converting from base.

0

Right, sorry I've been away for a while.
I've now made some changes and it seems that the conversion works correctly. Here is the code:
Test code in MyUI.java

UnitDef Meters = new UnitDef("M");//base value constructor
        UnitDef kM = new UnitDef("kM",1000);//KM conversion
        UnitDef mile = new UnitDef("Mile", 1609.34);
       /* UnitDef yard = new UnitDef("yards", 0.9144);*/

        double kMs = 5.0;
        double baseValue = kM.convertToBaseValue(kMs);
        double miles = mile.convertFromBaseValue(baseValue);
       /* double yards = yard.convertFromBaseValue(baseValue);*/

And the UnitDef.java

package com.vaadin.project.converterRedone;

import com.vaadin.ui.CustomComponent;

public class UnitDef extends CustomComponent{
    public String name;
    public double multiplier;
    public UnitDef(String name){//base unit
        this.name = name;
        this.multiplier = 1;
    }
    public UnitDef(String name, double multiplier){//overloaded constructor taking name and multiplier depending on conversion
        this.name = name;
        this.multiplier = multiplier;
    }
    public double convertToBaseValue(double value){
        value = value * multiplier;
        System.out.println("convertToBaseValue() and value is " + value);
        return value;

    }
    public double convertFromBaseValue(double value){
        value = value / multiplier;
        System.out.println("convertFromBaseValue() and value is " + value);
        return value;

    }
}

Can I start thinking about the GUI or should we implement all the possible conversions?

0

So far so good!

Since this is for fun, I would say quickly implement and test another conversion (ie a set of UnitDefs) such as weights to be sure that code is OK, then move on to the GUI.

In my opinion you need another class to hold all the UnitDefs for some measure (length, weight etc) and provide a simple interface for the GUI to use. But maybe start with the GUI using the UnitDefs directly and see where that starts to get tacky???

One small point: It's OK to have public variables in a class that is immutable (ie every variable is final - no possibility of them changing or being changed) but seeing variables public without final always rings an alarm bell for me.

Edited by JamesCherrill

0

that's fine, I'll try a few more conversions first.

but seeing variables public without final always rings an alarm bell for me.

Are you talking about these variables?

UnitDef Meters = new UnitDef("M");//base value constructor
        UnitDef kM = new UnitDef("kM",1000);//KM conversion
        UnitDef mile = new UnitDef("Mile", 1609.34);
        UnitDef yard = new UnitDef("yards", 0.9144);

As a side note, it might be that I will have to redo the whole thing again, some time soon, as there is the possibility that I could be using the same brief as practice at work, but that hasn't been decided yet. If that happens I will have to do it again, and of course I won't be using this code but I have to come up with something else... That's because I'm looking fo things to build at work as exercise you seem but will see what happens

Edited by Violet_82

0

No, that's just test code so anything goes. I was referring to

public class UnitDef extends CustomComponent{
    public String name;
    public double multiplier;
0

OK no worries.
I've also tried a new conversion and it works:

/*weights*/        
       UnitDef grams = new UnitDef("g");//base unit 
        UnitDef Kilo = new UnitDef("K",1000);
        UnitDef pound = new UnitDef("pound", 453.593); //pounds in 1 g
        UnitDef oz = new UnitDef("Oz", 28.349);              
        double kilograms = 5.0;
        double baseValue = Kilo.convertToBaseValue(kilograms);
        double pounds = pound.convertFromBaseValue(baseValue, "pound");
        /*weights*/

5kg returns 11.023097799128292 pound (I might round it up a bit, but maybe later).
So, now, if I think about the GUI (providing it's not too early of course) what would be the best way forward? Like having radio buttons as before, like km to miles, etc etc?
Also, in terms of classes, I have only UnitDef.java with the logic and the MyUI.java for the GUI: is that OK?

Edited by Violet_82

0

In my opinion you need another class to hold all the UnitDefs for some measure (length, weight etc) and provide a simple interface for the GUI to use. But maybe start with the GUI using the UnitDefs directly and see where that starts to get tacky???

0

quick question as I'm working with the UI. Like, the way I'm proceeding is to get the console to print ot messages when I click the submit, reset or radio button (km to miles etc).
Now, this is all in the GUI file but I was planning to replace those console statements with function calls, not sure whether those function definitions will sit inside the UnitDef class or inside the GUI one. What do you think?

0

Think about it like this:
Is displaying a message part of the behaviour of a unit definition in real life?
Uuit definitions have names, and factors or formulae that relate them to some fundamental unit (kilogram, meter, second), but they don't talk to you.
Is displaying a message part of the behaviour of a user interface in real life?
There's your answer.
The unit defs come into it when the UI needs to display a message (text box, whatever) that includes some converted unit info. At that point the UI delegates the unit conversion to a unit definition class - but nothing else.

Edited by JamesCherrill

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.