在方法

时间:2015-07-24 01:50:06

标签: java android annotations type-safety

我正在使用提供自定义View的库。我想创建一个只接受来自此库的自定义View的方法。

E.g。我有一个PieChart和一个TableChartTableChart扩展了LinearLayout,但PieChart扩展了一些扩展abstract的内部View图表。所以,我没有任何可以描述这两个对象的抽象类或接口。

目前我的方法如下:

void draw(View chart, ChartData data) {
    switch (data.getType()) {
        case PIE_CHART:
            PieChart<Numeric> pieChart = (PieChart<Numeric>) chart;
            // ...
            break;
        case TABLE_CHART:
            TableChart tableChart = (TableChart) chart;
            // ...
            break;
        // ...
    }
}

所以,我实际上可以将任何View作为chart参数传递,这看起来不太好。我在考虑在android中创建一些注释,例如@IntDef,但是对于类对象(https://developer.android.com/reference/android/support/annotation/IntDef.html)。我查看了源代码并尝试创建类似的东西,但它不起作用。我仍然可以传递任何View作为参数:

  @Retention(RetentionPolicy.SOURCE)
  @Target({ElementType.ANNOTATION_TYPE})
  @interface ClassDef {
    Class<? extends View>[] value() default {};
  }

  @Retention(RetentionPolicy.SOURCE)
  @ClassDef({PieChart.class, TableChart.class})
  @interface ChartView {}

  void draw(@ChartView View chart, ChartData data) // doesn't work

我对Java注释并不熟悉。有没有人知道是否可以创建这样的注释,只允许将特定的类作为参数传递? 也许还有其他方法可以实现类型安全?我无法更改库中类的源代码。

感谢。

修改

我提供了PieChartTableChart作为示例。在我的应用程序中,我有大约10种类型的图表。

4 个答案:

答案 0 :(得分:1)

您可以定义两个公共方法,一个采用PieChart,另一个采用TableChart。这将为您提供类型安全。如果存在共享逻辑,则可以从公共方法中调用private或protected方法。注释方法不起作用。

答案 1 :(得分:1)

编写注释是一个不错的选择,因为它不需要您更改源代码,也不会产生任何运行时开销,并且它可以为您提供编译时保证客户端正确使用库。 / p>

仅仅编写注释是不够的。编译时,还需要提供注释处理器,如果您滥用注释,则会发出编译错误。因此,您展示的代码是一个良好的开端,但缺少注释处理器。

您可以编写自己的注释处理器,也可以使用现有的注释处理器。您可能觉得有用的一个是Checker Framework。它似乎非常适合您的用例:您可以使用Subtyping Checker并使用诸如

之类的命令编译代码
javac -processor org.checkerframework.common.subtyping.SubtypingChecker \
-Aquals=ChartView MyFile.java

答案 2 :(得分:0)

您可以这样做的一种方法是:

void draw(View chart, ChartData data) throws Exception {
    if(!(chart instanceof TableChart || chart instanceof PieChart)){
        throw new IllegalArgumentException();
    }
    switch (data.getType()) {
        case PIE_CHART:
            PieChart<Numeric> pieChart = (PieChart<Numeric>) chart;
            // ...
            break;
        case TABLE_CHART:
            TableChart tableChart = (TableChart) chart;
            // ...
            break;
        // ...
    }
}

答案 3 :(得分:0)

因此,在研究了所有可能的解决方案之后,我决定使用构图。我在这些图表和表格周围创建了自己的包装器,然后实现了我自己的interface

interface AppChart {
    void setupChart();
    void bindChart(ChartData data);
}

class AppPieChart<T> implements AppChart {
    private PieChart<T> chart;

    public AppPieChart(PieChart<T> chart) {
        this.chart = chart;
    }

    @Override
    public void setupChart() {
        //...
    }

    // ...
}

class AppTableChart implements AppChart {
    private TableChart chart;

    public AppTableChart(TableChart chart) {
        this.chart = chart;
    }

    @Override
    public void setupChart() {
        //...
    }

    // ...
}

所以,我的draw方法现在是类型安全的:

void draw(AppChart chart, ChartData data) {
    switch (data.getType()) {
        case PIE_CHART:
            AppPieChart<Numeric> pieChart = (AppPieChart<Numeric>) chart;
            // ...
            break;
        case TABLE_CHART:
            AppTableChart tableChart = (AppTableChart) chart;
            // ...
            break;
        // ...
    }
}

感谢大家的帮助。