Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Singleton Factory

Tags:

java

generics

While reading online, I came across the following:

public interface UnaryFunction<T>
{
    T apply(T arg);
}

.......


private static UnaryFuntion<Object> ID_FUNC = new UnaryFunction<Object>
                                          {
                                             Object apply(Object arg)
                                             {
                                                  return arg;
                                             }
                                          };

public static <T> UnaryFunction<T> idFunction()
{
    return (UnaryFunction<T>) ID_FUNC;
}

In main:

public static void main(String[] args)
{
    String[] strings = {"Peter", "Paul", "Mary"};
    UnaryFunction<String> names = idFunction();
    for(String s : strings)
    {
        System.out.println(names.apply(s));
    }

    Number[] numbers = {1, 2.0, 3L};
    UnaryFunction<Number> nums = idFunction();
    for(Number n : numbers)
    {
        System.out.println(nums.apply(n));
    }
}

My question is, why do we need a generic interface here?

Would simply the following suffice:

public interface UnaryFunction
{
    Object apply(Object arg); //Object as return type and argument type, instead.
}

? What is the need here to use generics?

And, what is actually a generic singleton factory? What is it good for?

Thanks.

like image 918
Unheilig Avatar asked May 29 '14 20:05

Unheilig


1 Answers

The generic singleton factory is the idFunction in your example. Without it you would have a choice between two ugly alternatives, either require a cast wherever you use it, like this:

public class ExampleWithoutGenericSingletonFactory {

    static UnaryFunction<Object> ID_FUNC = new UnaryFunction<Object>() {
        public Object apply(Object arg) {
            return arg;
        }
    };

    public static void main(String[] args) {
        BigDecimal b = new BigDecimal("1234.1241234");
        BigDecimal b1 = (BigDecimal)(ID_FUNC.apply(b)); // have to cast here >_<
        System.out.println("engineeringstring val of b1 = " 
        + b1.toEngineeringString());
    }
}

or make separate implementations for every type you want to support:

public static UnaryFunction<String> ID_FUNC_STRING = new UnaryFunction<String>() {
    public String apply(String arg) {
        return arg;
    }
};

public static UnaryFunction<Number> ID_FUNC_NUM = new UnaryFunction<Number>() {
    public Number apply(Number arg) {
        return arg;
    }
};

public static UnaryFunction<BigDecimal> ID_FUNC_DECIMAL = new UnaryFunction<BigDecimal>() {
    public Number apply(BigDecimal arg) {
        return arg;
    }
};

giving you some ugly verbose cut-n-pasted code with a different name for every type that you have to keep straight. But since you know it's a pure function and the types get erased, you can have only one implementation (ID_FUNC) and have the singleton factory idFunction return it.

You would use this for cases where you have one function implementation that you want to be able to specify different types on, where the implementation is stateless.

The example could be better, since it only calls toString on the objects returned from the function call there's no demonstrated benefit from the factory. If the example showed using type-specific methods on the objects returned then the benefit might be more apparent.

An unchecked cast warning comes up when you do this, but it's safe to suppress it (which is what Joshua Bloch advises).

like image 154
Nathan Hughes Avatar answered Oct 08 '22 04:10

Nathan Hughes