继承了一些糟糕的Java泛型

时间:2011-11-07 21:28:18

标签: java generics

这是一个令人讨厌的问题,可能是设计很糟糕。

编写一组简单的图表组件(饼图,条形图和折线图),并对一些泛型的东西感到窒息。事先,我确信有很多Java API可以完成我在这里尝试做的事情(图表/报告/等等),但我对此感兴趣是一般的泛型问题;它涉及图表和事实的事实报告组件是微不足道的。

每个图表都继承自通用抽象基类Chart

public abstract class Chart<T extends ChartComponent>
{
    private List<T> components;

    // ...rest of the Chart class
}

我们拥有T extends ChartComponent的原因是因为每个图表子类都包含1个所谓的图表组件(条形图,线条,饼图等):

public abstract class ChartComponent
{
    private Color color;

    // .. rest of ChartComponent class
}

public class PieWedge extends ChartComponent
{
    double wedgeValue;

    // ... rest of PieWedge class
}

将这个设计放在一起:

public class PieChart extends Chart<PieWedge>
{
    // ... thus its list of ChartComponents is actually a List<PieWedge>
}

这样,PieChart不是通用的(也不应该是通用的),并且始终是Chart<PieWedge>类型。

我以前对条形图和折线图设置了相同的设置,分别定义为BarChart extends Chart<BarGroup>LineChart extends Chart<Line>(因为条形图由1组以上的条组成,并且折线图由以下组成: 1+行。

现在我想进一步抽象出条形图和折线图。这两个图表实际上是针对具有x轴和y轴的(x,y)笛卡尔图绘制的;这与没有针对任何此类轴绘制的饼图相反。

理想情况下,我想创建一个名为CartesianChart的新抽象类,其扩展Chart,然后BarChartLineChart都扩展CartesianChart。这个新的CartesianChart会引入新的属性(xAxisLabelgridTurnedOn等),这些属性在逻辑上适用于条形图/折线图而非饼图。

此外,要限制CartesianChart以便它只能chartComponentsBarGroup类型Line(而不是PieWedge),我想创建一个新的图表组件类型,如CartesianComponent extends ChartComponent,然后BarGroup / Line扩展它。这样做会阻止这样的代码编译:

LineChart lineChart = new LineChart();
lineChart.addLine(new PieWedge());

由于Line延伸CartesianComponent,但PieWedge仅延伸ChartComponent。因此,在遇到我的问题之前,我们有以下继承层次结构:

Chart
    CartesianChart
        BarChart
        LineChart
    PieChart

ChartComponent
    CartesianComponent
        BarGroup
        Line
    PieWedge

PieChart extends Chart<PieWedge>

CartesianChart extends Chart<CartesianComponent>

BarGroup extends CartesianComponent
Line extends CartesianComponent

BarChart extends CartesianChart<BarGroup>
LineChart extends CartesianChart<Line>

此设置存在的问题是,在BarChartLineChart上都会出现编译错误,抱怨CartesianChart不是通用的。 这完全有道理,但我不确定我能做些什么来解决它!

如果我尝试重新定义CartesianChart

public abstract class CartesianChart<T extends CartesianComponent> extends Chart<CartesianComponent>
{
    // ...
}

我通过条形码/折线图代码得到“类型不匹配”编译器错误。在错误的每个实例中,它都声明它期望List<CartesianComponent>类型的参数,而是找到List<BarGroup>List<Line>,并且它们不是合适的替代品。

希望这是CartesianChart和/或CartesianComponent的类定义中的某个快速修复。否则我可能不得不重新设计整个图表库。无论哪种方式,我都对任何和所有建议感兴趣,除了之类的“嘿,你为什么不尝试JFreeCharts或 ......”。同样,我对这里的解决方案感兴趣,因为它与解决各种类似的泛型问题有关;这涉及到报告/图表的事实是微不足道的。

提前感谢您提供的任何帮助!

3 个答案:

答案 0 :(得分:4)

您的Chart类包含您所说的List<T>,因此当您定义CartesianChart抽象类以扩展Chart<CartesianComponent>时,您就是{{1}真的是List<T>

真的,你想要的只是使用你在抽象类中定义它的泛型(即List<CartesianComponent>)。我会尝试这样做,看看它是如何工作的。

<T extends CartesianComponent>

答案 1 :(得分:0)

使用接口。

public interface IsAPieChart {

}

public interface IsACartesianChart {

}

他们甚至不需要任何方法。

addLine()的方法配置文件将显示为:

public void addLine(IsACartesianChart cartesianChart);

您的抽象类将为:

public class PieChart extends Chart<PieWedge> implements IsAPieChart
{
    // ... thus its list of ChartComponents is actually a List<PieWedge>
}

并使用IsACartesianChart以相同的方式标记CartesianChart。现在addLine()不接受PieChart的任何内容,因为没有PieChart实现IsACartesianChart接口,但是它将占用CartesianChart的子类,因为所有子类都实现了IsACartesianChart。

使用这样的接口是重新引入当一堆类追溯到同一个超类时丢失的区别的好方法。超类和子类形成严格的层次结构,而接口可以附加到您需要的任何地方。

答案 2 :(得分:0)

  

我们拥有T extends ChartComponent的原因是因为每个图表   子类将包含1个以上所谓的图表组件(条形图,   线条,饼楔等):

这是你的红鲱鱼,这里没有必要使用Generic。这是一个Composition问题,而不是Generics问题。

让您的列表看起来像:

private List<ChartComponent> components;

这是您应该需要的所有类型安全。