确保具有较低界限的泛型的成员之间的兼容性

时间:2015-06-28 16:54:54

标签: java generics

假设我正在构建一个通用的AssemblyLine类,它接受物理对象,测量它们,将它们放在纸板箱中,并用礼物包裹它们。我希望用户能够提供他们自己的对象测量策略(可能有些关心总体积,有些只关心对象的最长尺寸)以及他们自己的盒子选择策略(因为用户会知道哪个纸板最好他们想要使用的盒子。)

如果AssemblyLine可以接受对物理对象的超类进行操作的测量策略和盒子选择策略,那将会很棒。毕竟,如果用户的衡量策略适用于各种Dessert,我们应该让他们在AssemblyLine<Cake>AssemblyLine<Pie>使用相同的策略,对吗?

让我们从测量策略开始:

public interface PhysicalObjectMeasurementStrategy<T> {
    Measurement measureObject(T object);
}

很简单,我认为没有争议。接下来,我们要为框选择策略定义一个接口。这可能是我的第一个错误,但现在让我们继续讨论:

public interface CardboardBoxSelectionStrategy<T> {
    CardboardBoxSize chooseCardboardSizeForObject(T object, PhysicalObjectMeasurementStrategy<? super T> measurementStrategy);
}

我的想法是,我希望能够为我们可以测量的任何东西选择一个盒子。如果我们有馅饼的盒子选择策略和可以处理任何甜点的测量策略,那么能够在多个地方使用甜点测量策略是很好的。

现在,将它们组合成一条装配线:

public class AssemblyLine<T> {
    private final PhysicalObjectMeasurementStrategy<? super T> measurementStrategy;
    private final CardboardBoxSelectionStrategy<? super T> boxSelectionStrategy;

    // ...
    public void giftWrapObject(final T physicalObject) {
        // Here's where things fall apart:
        boxSelectionStrategy.chooseCardboardSizeForObject(physicalObject, this.measurementStrategy);

        // ...
    }
}

问题,尽我所知(这可能完全错误!),我们无法保证measurementStrategyboxSelectionStrategy都指的是同一个超类T,实际上可能指的是不相关的超类(或接口)。例如,我们可能会遇到以下情况:

  • PhysicalObjectMeasurementStrategy<Cylindrical>
  • CardboardBoxSelectionStrategy<Edible>
  • AssemblyLine<Cake>

这两种策略都适用于装配线,但由于并非所有Cylindrical个对象都是Edible(反之亦然),因此将测量策略传递给方框选择是没有意义的策略。

所以,重点是:在声明或构建AssemblyLine时,是否有一种很好的方法可以确保我们正在讨论相同或至少兼容的超类?如果没有,是否有另一种解决此问题的好方法(此问题是否有名称?),或者我是否需要重新考虑设计并可能在装配线中使用灵活性较低的组件?

非常感谢!

1 个答案:

答案 0 :(得分:0)

一种方法是使用单独的类型参数进行兼容的测量和盒子选择策略:

class AssemblyLine<M, B extends M> {
    private final PhysicalObjectMeasurementStrategy<M> measurementStrategy;
    private final CardboardBoxSelectionStrategy<B> boxSelectionStrategy;

    public void giftWrapObject(B physicalObject) {...

另一种方法可能是允许任何可以测量对象的测量策略传递给盒子选择策略:

<R extends T> CardboardBoxSize chooseCardboardSizeForObject(R object, 
        PhysicalObjectMeasurementStrategy<? super R> measurementStrategy);

或者您可以先测量物体然后将测量值传递给盒子选择状态。

我不知道这个问题是否有名称。