1

I'm developing some software where I'd like to allow the user to create and manage their own variables. I'd like to give the user the ability to create doubles, integers, and strings, and then manually set their values (all of this will be done through a UI). Right now I'm trying to decide on a model that would manage all of these user-defined variables.

My first thought was that it would be nice to have a Map that fetches variables by their name and use a "one-size-fits-all" 'Variable' class...

Map<String, Variable> myVars;

I thought to define the Variable class something like this...

public class Variable<T> 
{

private T value;

public void setValue(T value)
{
    this.value = value;
}

public T getValue()
{
    return value;
}

}

However, I think this approach requires me to define the map as Map<String, Variable<T> > but I don't want to choose a single type T for the entire map, but rather allow the map to contain a combination of integers, doubles, and strings.

A second thought was to create a container class that maintains three different maps, one each for strings, integers, and doubles. The three maps are insulated from the caller, and the caller merely needs to provide a String (the variable name) to a getter and the container would get the variable's value from the appropriate map. The container could also take care of issues like maintaining uniqueness of keys across all three maps.

A stub might look something like this...

public class VariableContainer {

private Map<String, Double> doubleVars = new HashMap();
private Map<String, String> stringVars = new HashMap();
private Map<String, Integer> intVars = new HashMap();

public Object get(String varName)
{
    if (doubleVars.containsKey(varName)) {
        return doubleVars.get(varName);
    } else if (stringVars.containsKey(varName)) {
        return stringVars.get(varName);
    } else if (intVars.containsKey(varName)) {
        return intVars.get(varName)
    } else {
        // varName not found
    }
}
}

However, now the caller of the get method must do inspection using instanceof to determine what kind of Object has been returned.

On that note, if inspection on the part of the caller is required, maybe it would be easiest to just stick with

Map<String, Object>

and forget about an abstract Variable class or a container class.

Perhaps yet another option is to return a wildcard as described in the answer to this question: Avoiding Returning Wildcard Types

Does anyone have any thoughts or experience on a good way to approach this? Thanks for any input.

Community
  • 1
  • 1
skrilmps
  • 625
  • 2
  • 10
  • 29
  • 1
    I think `Map>` is what you want, because `?` = `Object` and you need `?` to be either `String` or `Number`. Those have no methods in common except for those on `Object`. I don't like the `if-else` chain, those tend to be bad practice. Using your own `Variable` class seems OK, but it might depends how you use it later. – markspace Jul 19 '16 at 21:35
  • Thanks, I think it works. I'll make a follow-up post. – skrilmps Jul 20 '16 at 03:25

2 Answers2

0

OK the following appears to work:

public class Variable<T> 
{

    private T value;

    public void setValue(T value)
    {
        this.value = value;
    }

    public T getValue()
    {
        return value;
    }

    public String toString()
    {
        return value.toString();
    }
}

Map<String, Variable<?>> myVars = new HashMap<>();

Variable<Double> v1 = new Variable<>();
v1.setValue(3.0);

Variable<String> v2 = new Variable<>();
v2.setValue("hello");

myVars.put("doubleVar", v1);
myVars.put("stringVar", v2);

System.out.println("doubleVar = " + myVars.get("doubleVar"));
System.out.println("stringVar = " + myVars.get("stringVar"));

The above prints:

doubleVar = 3.0

stringVar = hello

skrilmps
  • 625
  • 2
  • 10
  • 29
0

You can us Function Overriding.

class Container{
   // get();
}
class StringContiner extends Container{
  // get() return string;
}
class IntContainer extends Container{
   // get() return return int;
}
class DoubleContainer extends Container{
  // get() return double;
}
Zigri2612
  • 2,279
  • 21
  • 33