2011-11-07 13 views
6

Questo è un brutto problema e potrebbe essere che il design sia solo negativo.Ereditato alcuni generici Java errati

Scrittura di un set di componenti grafici semplici (grafico a torta, barre & e soffocamento su alcune cose generiche. In anticipo, sono sicuro che ci sono molte API Java per fare esattamente quello che sto cercando di fare qui (creazione di grafici/report/ecc.), Tuttavia sono interessato a questo come un problema generico generale; il fatto che coinvolga i grafici dei componenti di reporting & è banale.

Ogni tabella eredita da una generica classe di base astratta Chart:

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

    // ...rest of the Chart class 
} 

Il motivo per cui abbiamo T extends ChartComponent è perché ogni sottoclasse grafico sarà composto da 1+ cosiddetti componenti del grafico (bar, linee , fette di torta, ecc):

public abstract class ChartComponent 
{ 
    private Color color; 

    // .. rest of ChartComponent class 
} 

public class PieWedge extends ChartComponent 
{ 
    double wedgeValue; 

    // ... rest of PieWedge class 
} 

Mettendo insieme questo progetto:

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

In questo modo, PieChart non è generico (né dovrebbe essere) ed è sempre di tipo Chart<PieWedge>.

I precedentemente avevano lo stesso setup per barre e a linee grafici, che sono stati definiti come BarChart extends Chart<BarGroup> e LineChart extends Chart<Line> rispettivamente (poiché un grafico a barre è costituito da 1+ gruppi di barre, e un grafico linea consiste di linee 1+).

Ora voglio astrarre ulteriormente i grafici di barre e linee. Entrambi questi grafici sono in realtà tracciati rispetto a un grafico cartesiano (x, y) con assi xey; questo è in contrasto con un grafico a torta che non è tracciato contro tali assi.

Idealmente, ho voluto creare una nuova classe astratta denominata CartesianChart che si estendeva Chart, e poi hanno BarChart e LineChart entrambi estendono CartesianChart. Questo nuovo CartesianChart introdurrebbe nuove proprietà (xAxisLabel, gridTurnedOn, ecc.) Che si applicano logicamente ai grafici a barre/linea ma non ai grafici a torta.

Inoltre, per limitare CartesianChart modo che potesse avere solo chartComponents di tipo BarGroup o Line (e non PieWedge), desidero creare un nuovo tipo di componente diagramma come CartesianComponent extends ChartComponent, e poi BarGroup/Line estendono questo. In questo modo avrebbe impedito il codice come questo da compilare:

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

Dal Line estende CartesianComponent, ma PieWedge si estende solo ChartComponent. Così, prima di arrivare al mio problema abbiamo la seguente gerarchia di ereditarietà:

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> 

Il problema con questa configurazione è che su entrambi BarChart e LineChart dà un errore del compilatore lamentano che CartesianChart non è generica. Questo ha senso, ma non sono sicuro di cosa posso fare per risolverlo!

Se provo a ridefinire CartesianChart:

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

ottengo "Tipo non corrispondente" errori di compilazione per tutto il mio codice grafico a barre/linea. In ogni istanza dell'errore, si afferma che è in attesa di argomenti di tipo List<CartesianComponent> ma che invece ha trovato List<BarGroup> o List<Line> e che non sono sostituti idonei.

Si spera che questa sia una soluzione rapida da qualche parte nella definizione di classe di CartesianChart e/o CartesianComponent. In caso contrario, potrei dover riprogettare l'intera libreria di grafici. Ad ogni modo, sono interessato a tutti i suggerimenti, eccetto quelli come "Ehi, perché non provi solo JFreeCharts o ...". Ancora una volta, mi interessa la soluzione qui in quanto riguarda la risoluzione di una vasta gamma di problemi generici simili; il fatto che ciò riguardi il reporting/la creazione di grafici è banale.

Grazie in anticipo per qualsiasi aiuto!

+0

Cosa stai cercando di ottenere rendendo 'Chart' generico? In altre parole, perché non definire solo componenti di classe Chart {Lista privata ; } '? –

+0

'CartesianChart classe pubblica astratta estende il grafico '? – digitaljoel

+0

Grazie per i suggerimenti qui. Proverò entrambi i tuoi suggerimenti qui. Per favore vedi il mio commento qui sotto @ la risposta di nicholas.hauschild sulla mia paura che l'estensione del grafico non impedisca le sottoclassi che fanno di Chart dove T non estende ChartComponent. – IAmYourFaja

risposta

4

La classe Chart contiene il List<T> di cui parli, così quando si si definisce la classe astratta CartesianChart di estendere Chart<CartesianComponent>, lei sta dicendo che è davvero List<T>List<CartesianComponent>.

In realtà, quello che vuoi è usare semplicemente il generico come lo hai definito nella classe astratta (ovvero, <T extends CartesianComponent>). Vorrei provare a fare questo e vedere come funziona.

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

Questo è un ottimo suggerimento (e grazie!), Tuttavia temo che questo consenta la definizione di sottoclassi in questo modo: lo schema di classe pubblica estende il grafico , dove Widget non è una sottoclasse di ChartComponent. È importante che tutti i tipi "T" ereditino (ad un certo punto) da ChartComponent. – IAmYourFaja

+0

In realtà non lo sarebbe, perché hai già definito 'T' in questo ambito essere limitato a' CartesianComponent' (per 'CartesianChart '). Prova il mio suggerimento e poi prova ad aggiungere un "Widget" ad esso ... –

+0

Fantastico, fantastico, fantastico. Grazie ancora! – IAmYourFaja

0

Utilizzare interfacce.

public interface IsAPieChart { 

} 

public interface IsACartesianChart { 

} 

Non hanno nemmeno bisogno di alcun metodo.

tuo profilo metodo per AddLine() sarebbe il seguente:

public void addLine(IsACartesianChart cartesianChart); 

vostre classi astratte avrebbero letto:

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

E utilizzare IsACartesianChart per segnare CartesianChart nello stesso modo. Ora addLine() non accetterà nulla di PieChart perché nessun PieChart implementa l'interfaccia IsACartesianChart, ma prenderà qualcosa di una sottoclasse di CartesianChart perché tutte le sottoclassi implementano IsACartesianChart.

L'utilizzo di interfacce come questa è un ottimo modo per reintrodurre distinzioni che sono state perse quando un gruppo di classi fa riferimento alla stessa superclasse. Le superclassi e le sottoclassi formano una gerarchia rigorosa, mentre le interfacce possono essere collegate ovunque ne abbiate bisogno.

0

Il motivo per cui abbiamo T extends ChartComponent è perché ogni grafico sottoclasse sarà composto 1+ cosiddette componenti del grafico (bar, linee, cunei torta, etc.):

Questo è le tue red-aring, non c'è bisogno di usare un Generic qui. Questo è un problema Composition, non un problema Generics.

Basta fare lista il tuo look come:

private List<ChartComponent> components; 

Ciò è tanto il tipo di sicurezza si dovrebbe aver bisogno.

+0

Grazie! Proverò questo suggerimento più tardi questa settimana, quando ho una possibilità. – IAmYourFaja