简体   繁体   中英

Java - Factory Method that returns generic Base type

I'm trying to genericize a factory method that returns a generic Base class. It works, but I'm getting the "BaseClass is a raw type..." warning.

I've read through the Java docs on Generic methods, but I'm still not quite getting how to accomplish this.

Here's some code:

Class #1

//base abstract class
public abstract class BaseFormatter<T>
{
    public abstract String formatValue(T value);
}

Class #2

//two implementations of concrete classes
public class FooFormatter extends BaseFormatter<Integer>
{
    @Override
    public String formatValue(Integer value)
    {
        //return a formatted String
    }
}

Class #3

public class BarFormatter extends BaseFormatter<String>
{
    @Override
    public String formatValue(String value)
    {
        //return a formatted String
    }
}

Factory Method in a separate class

public static BaseFormatter getFormatter(Integer unrelatedInteger)
{
    if (FOO_FORMATTER.equals(unrelatedInteger))
        return new FooFormatter();
    else if (BAR_FORMATTER.equals(unrelatedInteger))
        return new BarFormatter();
    //else...
}

Call to the Factory Method from elsewhere in the code

BaseFormatter<Integer> formatter = getFormatter(someInteger);
formatter.formatValue(myIntegerToFormat);

The problem is the getFormatter() method warns that BaseFormatter is a raw type, which it is. I've tried various things like BaseFormatter et al. I, of course, want the return type to be generic, as in the declared BaseFormatter in the calling method.

Note that the formatter type is not based on class type. eg not all Integer values are formatted with a FooFormatter. There are two or three different ways an Integer (or String, or List) can be formatted. That's what the param unrelatedInteger is for.

Thanks in advance for any feedback.

If getFormatter is defined in BaseFormatter, then use:

public static BaseFormatter<T> getFormatter(Integer unrelatedInteger)

If getFormatter is defined in another class than BaseFormatter, then use:

public static BaseFormatter<?> getFormatter(Integer unrelatedInteger)

You're actuaaly saying that there's no connection between the typed parameter of BaseFormatter and the unrelatedInteger that is passed as argument to the getFormatter method.

I get some other warning:

Uncehcked Assignment: BaseFormatter to BaseFormatter<Integer>

This warning is worse than the one you indicated. It warns that this user code might try to insert a BaseFormatter<String> into BaseFormatter<Integer> , something that will be noticed only when fails in runtime... Consider a user accidentally uses you factory method like such:

BaseFormatter<Integer> myUnsafeFormatter =
        FormatterFactory.getFormatter(unrelatedIntegerForBarFormatter);

The compiler cannot relate the unrelatedInteger with the parameterized type of the returned BaseFormatter .

Alternitavely, I'd let the user explicitly use the concrete formatter constructors. Any common code shared by all formatters could be put into FormatterUtils class (just don't let that utils class to grow to much...).

Some type systems in academic languages can express a so-called dependent sum. Java certainly cannot; so what, sensibly, could be the type of the object returned by the getFormatter method? The best we can do is BaseFormatter< ? extends Object > BaseFormatter< ? extends Object > , or BaseFormatter< ? > BaseFormatter< ? > for short, as Integer and String have only Object in common.

I think the original post begs the question, why must we use an integer to decide what formatter to return, and if the type of formatter would not be known by the caller, why would the caller need a stronger variable type than BaseFormatter< ? > BaseFormatter< ? > ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM