Skip to content
Advertisement

Avoid cast in generic factories

Suppose I have a class structure looking like this:

public abstract class Interval<I extends Interval<?>> {
    public static final IntervalFactory<? extends Interval<?>> factory = null;

    // some variables and methods
}

public class Week extends Interval<Week> {
    public static final IntervalFactory<Week> factory = new WeekFactory();
    
    // some variables and methods
}

public interface IntervalFactory<I extends Interval> {
    I containing(LocalDate date);
    List<I> containing(LocalDate startDate, LocalDate endDate);
}

public class WeekFactory implements IntervalFactory<Week> {
    @Override
    public Week containing(LocalDate date) {
        // implementation
    }

    @Override
    public List<Week> containing(LocalDate startDate, LocalDate endDate) {
        // implementation
    }
}

Now I have a class that uses those intervals and factories:

public class SomeClass<I extends Interval<?>> {
    private final IntervalFactory<I> intervalFactory;

    public DistributorForSlowQuantifier() {
        this.intervalFactory = (IntervalFactory<I>) I.factory;
    }
    
    public Map<I, Double> distribute(double value) {
        // implementation
    }
}

Is this the right way of approaching the problem if a class needs to create instances from a type variable?

Is there a way around the cast in the SomeClass constructor?

The obvious things don’t work – having a wildcard as the type parameter of intervalFactory in SomeClass loses all the type information, the factories are static, so I cannot use I as a type parameter, and if I don’t mark them as static, I need an instance of I to access the factory…

The cast is absolutely safe, as long as Interval implementations choose the “corresponding” factory, but it still feels… wrong.

Advertisement

Answer

The cast in the SomeClass constructor doesn’t even work. It’ll always use Interval.factory, whether or not that corresponds to the kind of factory you want. I.factory does not do what you think.

By far the most common and sensical approach: to pass in the appropriate factory to the constructor. You can add some syntactic sugar around this with static imports and static factory methods to make it look like e.g. new DistributorForSlowQuantifier(days()) or the like. There are other, much more convoluted and messy workarounds, but all things considered, they’re worse.

Advertisement