2011-11-07 28 views
6

Đây là một vấn đề khó chịu và có thể thiết kế chỉ là xấu.Thừa kế một số chi tiết Java xấu

Viết một tập hợp các thành phần biểu đồ đơn giản (biểu đồ dạng thanh, thanh &) và đang bị nghẹt thở trên một số nội dung chung. Trước tiên, tôi chắc chắn có nhiều API Java để thực hiện chính xác những gì tôi đang cố gắng làm ở đây (biểu đồ/báo cáo/v.v.), tuy nhiên tôi quan tâm đến vấn đề này như một vấn đề chung về generics; thực tế là nó liên quan đến các biểu đồ & các thành phần báo cáo là tầm thường.

Mỗi biểu đồ kế thừa từ một lớp cơ sở trừu tượng chung chung Chart:

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

    // ...rest of the Chart class 
} 

Lý do tại sao chúng tôi có T extends ChartComponent là vì mỗi lớp biểu đồ sẽ bao gồm 1+ cái gọi là thành phần biểu đồ (thanh, dây chuyền , nêm bánh, vv):

public abstract class ChartComponent 
{ 
    private Color color; 

    // .. rest of ChartComponent class 
} 

public class PieWedge extends ChartComponent 
{ 
    double wedgeValue; 

    // ... rest of PieWedge class 
} 

Đưa thiết kế này với nhau:

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

Bằng cách này, PieChart không phải là chung chung (cũng không nên là) và luôn là loại Chart<PieWedge>.

Trước đây tôi đã thiết lập tương tự cho biểu đồ thanh và đường, được định nghĩa tương ứng là BarChart extends Chart<BarGroup>LineChart extends Chart<Line> (vì biểu đồ thanh bao gồm hơn 1 nhóm thanh và biểu đồ đường bao gồm 1+ dòng).

Bây giờ tôi muốn trừu tượng hóa Biểu đồ thanh và đường hơn nữa. Cả hai biểu đồ này thực sự được vẽ trên biểu đồ Descartes (x, y) với các trục x và y; điều này trái với biểu đồ hình tròn không được vẽ với bất kỳ trục nào như vậy.

Lý tưởng nhất, tôi muốn tạo ra một lớp trừu tượng mới có tên gọi CartesianChart mà mở rộng Chart, và sau đó có BarChartLineChart cả mở rộng CartesianChart. CartesianChart mới này sẽ giới thiệu các thuộc tính mới (xAxisLabel, gridTurnedOn, v.v.) áp dụng hợp lý cho biểu đồ thanh/đường nhưng không áp dụng cho biểu đồ hình tròn.

Bên cạnh đó, để hạn chế CartesianChart để nó chỉ có thể có chartComponents loại BarGroup hoặc Line (và không PieWedge), tôi muốn tạo ra một loại thành phần biểu đồ mới như CartesianComponent extends ChartComponent, và sau đó có BarGroup/Line mở rộng đó. Làm như vậy sẽ ngăn chặn mã như thế này từ biên soạn:

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

Kể từ Line kéo dài CartesianComponent, nhưng PieWedge chỉ kéo dài ChartComponent. Do đó, trước khi đến vấn đề của tôi, chúng tôi có hệ thống phân cấp thừa kế sau:

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> 

Vấn đề với thiết lập này là trên cả BarChartLineChart nó mang lại cho một lỗi biên dịch phàn nàn rằng CartesianChart là không chung chung. Điều này có ý nghĩa hoàn toàn, nhưng tôi không chắc mình có thể làm gì để sửa lỗi!

Nếu tôi cố gắng để tái xác định CartesianChart:

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

tôi nhận được "loại không phù hợp" lỗi biên dịch tất cả thông qua mã biểu đồ bar/dòng của tôi. Trong mọi trường hợp của lỗi, nó nói rằng nó đang chờ đối số của loại List<CartesianComponent> nhưng thay vào đó tìm thấy List<BarGroup> hoặc List<Line> và chúng không phải là sản phẩm thay thế phù hợp.

Hy vọng rằng đây là cách khắc phục nhanh ở đâu đó trong định nghĩa lớp học CartesianChart và/hoặc CartesianComponent. Nếu không, tôi có thể phải thiết kế lại toàn bộ thư viện biểu đồ. Dù bằng cách nào, tôi quan tâm đến bất kỳ và tất cả các đề xuất, ngoại trừ những cái như "Xin chào, tại sao bạn không thử JFreeCharts hoặc ...". Một lần nữa, tôi quan tâm đến giải pháp ở đây vì nó liên quan đến việc giải quyết một loạt các vấn đề generics tương tự; thực tế là điều này liên quan đến báo cáo/biểu đồ là tầm thường.

Cảm ơn trước vì bất kỳ và tất cả trợ giúp!

+0

Bạn đang cố gắng thực hiện điều gì bằng cách tạo 'Bảng xếp hạng' chung? Nói cách khác, tại sao không chỉ định nghĩa các thành phần 'class Chart {private List ; } '? –

+0

'lớp trừu tượng công khai CartesianChart mở rộng Biểu đồ '? – digitaljoel

+0

Cảm ơn bạn đã đề xuất ở đây. Tôi sẽ thử cả hai đề xuất của bạn ở đây. Xin vui lòng xem bình luận của tôi dưới đây @ nicholas.hauschild của câu trả lời về nỗi sợ hãi của tôi mà mở rộng Biểu đồ sẽ không ngăn chặn các lớp con làm Chart của nơi T không mở rộng ChartComponent. – IAmYourFaja

Trả lời

4

lớp Chart của bạn có chứa các List<T> mà bạn nói đến, vì vậy khi bạn bạn xác định CartesianChart lớp trừu tượng của bạn để mở rộng Chart<CartesianComponent>, bạn đang nói rằng List<T> thực sự List<CartesianComponent> là.

Thực sự, những gì bạn muốn là chỉ sử dụng chung chung như bạn đã xác định nó trong lớp trừu tượng của bạn (nghĩa là, <T extends CartesianComponent>). Tôi sẽ cố gắng làm điều này và xem nó hoạt động như thế nào.

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

Đó là một gợi ý rất tốt (và cảm ơn bạn!), Tuy nhiên tôi lo rằng điều này sẽ cho phép các lớp con được định nghĩa như vậy: Sơ đồ lớp công khai mở rộng Biểu đồ , trong đó Widget không phải là một lớp con ChartComponent. Điều quan trọng là tất cả các loại "T" của kế thừa (tại một số điểm) từ ChartComponent. – IAmYourFaja

+0

Nó sẽ không thực sự, bởi vì bạn đã xác định 'T' trong phạm vi này được giới hạn trong' CartesianComponent' (mỗi 'CartesianChart '). Hãy thử đề xuất của tôi và sau đó thử thêm một 'Widget' vào nó ... –

+0

Tuyệt vời, tuyệt vời, tuyệt vời. Cám ơn bạn một lần nữa! – IAmYourFaja

0

Sử dụng giao diện.

public interface IsAPieChart { 

} 

public interface IsACartesianChart { 

} 

Chúng thậm chí không cần bất kỳ phương pháp nào.

hồ sơ phương pháp của bạn cho addLine() sẽ đọc:

public void addLine(IsACartesianChart cartesianChart); 

lớp trừu tượng của bạn sẽ đọc:

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

Và sử dụng để đánh dấu IsACartesianChart CartesianChart trong cùng một cách. Bây giờ addLine() sẽ không chấp nhận bất cứ thứ gì của PieChart vì không có PieChart thực hiện giao diện IsACartesianChart, nhưng nó sẽ lấy bất kỳ thứ gì của một lớp con của CartesianChart vì tất cả các lớp con thực thi IsACartesianChart.

Sử dụng các giao diện như thế này là một cách tuyệt vời để giới thiệu lại các khác biệt đã bị mất khi một loạt các lớp theo dõi trở lại cùng một lớp cha. Các lớp siêu lớp và các lớp con tạo thành một hệ thống phân cấp nghiêm ngặt, trong khi các giao diện có thể được gắn vào bất cứ nơi nào bạn cần chúng.

0

Lý do tại sao chúng tôi có T extends ChartComponent là vì mỗi biểu đồ lớp con sẽ được bao gồm 1+ cái gọi là thành phần biểu đồ (quán bar, dòng, nêm bánh, vv):

Đây là cá trích đỏ của bạn, không cần sử dụng Generic ở đây. Đây là sự cố Composition, không phải là sự cố Generics.

Chỉ cần chắc danh sách cái nhìn của bạn như:

private List<ChartComponent> components; 

Đây là tất cả sự an toàn loại bạn nên cần.

+0

Cảm ơn! Tôi sẽ cố gắng gợi ý này vào cuối tuần này khi tôi có cơ hội. – IAmYourFaja