Inherited some Java generics

This is an unpleasant problem, and maybe the design is just bad.

Writing a set of simple chart components (pie, bar and line charts) and strangling some generics. In advance, I am sure that there are many Java APIs to do exactly what I am trying to do here (charts / reports / etc.), however, I am interested in this as a general generic problem; the fact that it includes charts and reporting components is trivial.

Each chart inherits from a generic Chart abstract base class:

 public abstract class Chart<T extends ChartComponent> { private List<T> components; // ...rest of the Chart class } 

The reason we have T extends ChartComponent is because each subclass of the chart will consist of 1+ so-called chart components (bars, lines, wedge blades, etc.):

 public abstract class ChartComponent { private Color color; // .. rest of ChartComponent class } public class PieWedge extends ChartComponent { double wedgeValue; // ... rest of PieWedge class } 

Combining this project:

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

Thus, PieChart not generic (and should not) and is always of type Chart<PieWedge> .

Earlier, I had the same setting for line and line charts, which were defined as BarChart extends Chart<BarGroup> and LineChart extends Chart<Line> respectively (since the histogram consists of 1+ groups of bars, and the line diagram consists of 1 + lines )

Now I want to drop the Bar and Line strings even more. Both of these diagrams are actually plotted on a (x, y) map of Cartesian with x- and y-axes; this is in contrast to a pie chart that is not plotted against any such axes.

Ideally, I wanted to create a new abstract class called CartesianChart , which extended Chart and then had BarChart and LineChart and CartesianChart extensions. This new CartesianChart will introduce new properties ( xAxisLabel , gridTurnedOn , etc.) that are logically applicable to bar / line charts, but not pie charts.

Also, to restrict CartesianChart so that it can only have chartComponents like BarGroup or Line (and not PieWedge ), I would like to create a new type of chart component like CartesianComponent extends ChartComponent , and then BarGroup / Line distribute it. This will prevent compilation of such code:

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

Since Line continues CartesianComponent , but PieWedge distributed only by ChartComponent . Thus, before moving on to my problem, we have the following inheritance hierarchy:

 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> 

The problem with this setting is that on BarChart and LineChart it gives a compiler error, complaining that CartesianChart not shared. It makes sense, but I'm not sure what I can do to fix it.

If I try to override CartesianChart :

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

I get compiler errors like mismatch through my line / line code. In each case of error, he claims that he expects arguments of type List<CartesianComponent> , but instead has found List<BarGroup> or List<Line> and that they are not suitable for replacement.

Hopefully this is a quick fix somewhere in the CartesianChart and / or CartesianComponent class definition. Otherwise, I may have to redesign the entire charting library. In any case, I am interested in any offers, except , such as "Hey, why don't you just try JFreeCharts or ...". Again, I am interested in the solution here, since it is related to the solution of a wide range of similar generics; the fact that this includes reporting / mapping is trivial.

Thanks in advance for any help!

+6
source share
3 answers

Your Chart class contains the List<T> you are talking about, so when you define the abstract CartesianChart class for the Chart<CartesianComponent> extension, you say that List<T> really List<CartesianComponent> .

Indeed, you just need to use the generic as you defined it in your abstract class (i.e. <T extends CartesianComponent> ). I would try to do this and see how it works.

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

Use interfaces.

 public interface IsAPieChart { } public interface IsACartesianChart { } 

They do not even need any methods.

Your method profile for addLine () will read:

 public void addLine(IsACartesianChart cartesianChart); 

Your abstract classes will read:

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

And use IsACartesianChart to mark CartesianChart in the same way. Now addLine () will not accept anything from PieChart, because PieChart does not implement the IsACartesianChart interface, but it will take something from the CartesianChart subclass, because all subclasses implement IsACartesianChart.

Using such interfaces is a great way to repeat the differences that were lost when the class group returned to the same superclass. Superclasses and subclasses form a strict hierarchy, and interfaces can be attached where you need it.

0
source

The reason we have T extends ChartComponent is because each chart subclass will consist of 1+ so-called chart components (bars, lines, pie wedges, etc.):

This is your red herring, there is no need to use Generic. This is a Composition issue, not a Generics issue.

Just create your list:

 private List<ChartComponent> components; 

That is all you need.

0
source

Source: https://habr.com/ru/post/900975/


All Articles