2011-11-07 6 views
6

これは厄介な問題であり、デザインがひどいことかもしれません。いくつかの悪いJavaジェネリックを継承しました

単純なグラフコンポーネント(円、棒グラフ、&折れ線グラフ)のセットを書くといくつかのジェネリックスのものに窒息です。事前に、私がここでやろうとしていることを正確に行うための多くのJava APIがあると確信していますが、一般的なジェネリックの問題として興味があります。図表&レポートコンポーネントが含まれているという事実は簡単です。

すべてのチャートは、一般的な抽象基底クラスChartから継承:

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

    // ...rest of the Chart class 
} 

すべてのグラフのサブクラスは1+いわゆるチャートコンポーネント(棒、線で構成されますので、我々はT extends ChartComponentを持っている理由はあります、パイウェッジなど):

public abstract class ChartComponent 
{ 
    private Color color; 

    // .. rest of ChartComponent class 
} 

public class PieWedge extends ChartComponent 
{ 
    double wedgeValue; 

    // ... rest of PieWedge class 
} 

は、この設計をまとめる:

0123を

このように、PieChartは一般的ではなく(また、そうでなければなりません)、常にタイプChart<PieWedge>です。

バーチャートは棒グラフと棒グラフの設定が同じです(棒グラフは1+棒グラフで構成されており、折れ線グラフは1+線で構成されているため)BarChart extends Chart<BarGroup>LineChart extends Chart<Line>とそれぞれ定義されていました。

今、バーとラインのグラフをさらに抽象化したいと思います。これらのチャートは、実際には、x軸とy軸を持つ(x、y)デカルトグラフに対してプロットされています。これは、そのような軸に対してプロットされていない円グラフとは対照的です。

理想的には、私はChartを拡張CartesianChartと呼ばれる新しい抽象クラスを作成し、両方がCartesianChartを拡張BarChartLineChartを持っていると思いました。この新しいCartesianChartは、論理的に棒グラフと線グラフに適用され、円グラフには適用されない新しいプロパティ(xAxisLabelgridTurnedOnなど)を導入します。

また、それが唯一のタイプBarGroup又はLinechartComponents(としないPieWedge)を有することができるようにCartesianChartを制限するために、私はCartesianComponent extends ChartComponentような新しいグラフコンポーネントタイプを作成したい、その後BarGroup/Lineはそれを延ばすであろう。 LineCartesianComponentを拡張するので

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

が、PieWedgeChartComponentを拡張します。そうすることで、コンパイルから、このようなコードを防止するであろう。

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やを試してみてください。繰り返しますが、ここでは、同様のジェネリック問題の広範な解決に関連して、ここでのソリューションに興味があります。これが報告/チャート作成を伴うという事実は自明です。

ご協力いただきありがとうございます!

+0

'Chart'を一般的にすることで何を達成しようとしていますか?言い換えれば、 'class Chart {private List コンポーネント; } '? –

+0

'public abstract class CartesianChart はグラフ'を拡張しますか? – digitaljoel

+0

ここに提案していただきありがとうございます。私はここであなたの提案をお試しください。下の私のコメントを参照してください。下のコメントをご覧ください。Chart を拡張することで、TがChartComponentを拡張していないChartのサブクラスを防ぐことができないという私の恐怖についての答えがnicholas.hauschildの答えです。 – IAmYourFaja

答えて

4

あなたChartクラスは、あなたが話すList<T>が含まれているので、あなたがChart<CartesianComponent>を拡張するためにあなたのCartesianChart抽象クラスを定義するとき、あなたはList<T>が本当にList<CartesianComponent>であることを言っています。

実際には、抽象クラス(つまり、<T extends CartesianComponent>)で定義したとおり、ジェネリックを使用するだけです。私はこれをやろうとして、それがどのように機能するか見る。

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

これは非常に良い提案です(ありがとうございます)。しかし、これでサブクラスを次のように定義できるようになるのではないかと心配しています。public class DiagramはChart を拡張しています(WidgetはChartComponentサブクラスではありません)。すべての型 "T"がChartComponentから(ある時点で)継承することが重要です。 – IAmYourFaja

+0

このスコープで 'CartesianComponent'(CartesianChart )に制限されるように' T'を既に定義しているので、実際にはありません。私の提案を試し、それに 'ウィジェット 'を追加してみてください... –

+0

素晴らしい、素晴らしい、素晴らしい。ありがとうございました! – IAmYourFaja

0

インターフェイスを使用します。

public interface IsAPieChart { 

} 

public interface IsACartesianChart { 

} 

これらのメソッドにもメソッドは必要ありません。

addLineのためのあなたのメソッドプロファイルは、()読んでいました:

public class PieChart extends Chart<PieWedge> implements IsAPieChart 
{ 
    // ... thus its list of ChartComponents is actually a List<PieWedge> 
} 
を同じ方法でたCartesianChartをマークするIsACartesianChartを使用します。

public void addLine(IsACartesianChart cartesianChart); 

あなたの抽象クラスを読んでいました。 addLine()は、PieChartがIsACartesianChartインタフェースを実装していないため、何も受け付けませんが、すべてのサブクラスがIsACartesianChartを実装するため、CartesianChartのサブクラスの何かを取ります。

このようなインターフェイスを使用すると、一連のクラスが同じスーパークラスにトレースバックするときに失われた識別情報を再導入することができます。スーパークラスとサブクラスは厳密な階層を形成しますが、必要なときはいつでもインタフェースを取り付けることができます。

0

すべてのチャート サブクラスは1+いわゆるチャートコンポーネント(バー、 ライン、パイウェッジなど)で構成されますので、我々はT extends ChartComponentを持っている理由は次のとおりです。

これはさあなたの赤ちゃんは、ここでジェネリックを使う必要はありません。これはCompositionの問題で、Genericsの問題ではありません。

ちょうどあなたのリストは次のようになります。これは、あなたが必要とする必要があるすべての型の安全性である

private List<ChartComponent> components; 

+0

ありがとう!今週末に私がチャンスを持っているときにこの提案を試してみましょう。 – IAmYourFaja

関連する問題