避免在通用工厂中铸造

cha*_*aws 0 java generics

假设我有一个如下所示的类结构:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我有一个使用这些间隔和工厂的类:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

如果类需要从类型变量创建实例,这是解决问题的正确方法吗?

有没有办法绕过SomeClass构造函数中的强制转换?

明显的事情不起作用 - 使用通配符作为 IntervalFactory 的类型参数会SomeClass丢失所有类型信息,工厂是静态的,所以我不能用作I类型参数,如果我不将它们标记为静态,我需要一个 I 的实例来访问工厂......

强制转换是绝对安全的,只要 Interval 实现选择“相应”工厂,但它仍然感觉......错误。

Lou*_*man 5

构造函数中的强制转换SomeClass甚至不起作用。它总是使用Interval.factory,无论它是否对应于您想要的工厂类型。 I.factory不做你的想法。

到目前为止,最常见和最有意义的方法是:将适当的工厂传递给构造函数。您可以使用静态导入和静态工厂方法在其周围添加一些语法糖,使其看起来像例如new DistributorForSlowQuantifier(days())或类似的东西。还有其他更复杂、更混乱的解决方法,但综合考虑,它们更糟糕。