2015-07-24 4 views
1

Я использую библиотеку, которая предоставляет пользовательские View s. Я хочу создать метод, который принимает только пользовательские View s из этой библиотеки.Тип безопасного параметра в методе

E.g. У меня есть PieChart и TableChart. TableChart extends 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, который не выглядит хорошо. Я думал создать некоторую аннотацию, такую ​​как @IntDef в android, но для объектов класса (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 

Я не очень знаком с ява аннотаций, хотя. Кто-нибудь знает, возможно ли создать такую ​​аннотацию, которая позволит передавать только определенные классы в качестве параметра? Возможно, существует какой-то другой подход к обеспечению безопасности типа? Я не могу изменить исходный код классов внутри библиотеки.

Спасибо.

РЕДАКТИРОВАТЬ

я предоставил PieChart и TableChart в качестве примеров. В моем приложении у меня около 10 типов диаграмм.

ответ

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; 
     // ... 
    } 
} 

Спасибо всем за вашу помощь.

1

Вы можете определить два общедоступных метода, один из которых принимает PieChart и тот, который принимает TableChart. Это даст вам безопасность типа. Если есть общая логика, вы можете вызвать частный или защищенный метод из ваших общедоступных методов. Подход аннотации не будет работать.

+0

хорошо, спасибо. Ваш подход хорош, если у меня есть только эти две диаграммы, но, к сожалению, у меня около 10 типов, которые дадут мне 10 методов. Любые другие идеи? –

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; 
     // ... 
    } 
} 
+0

Это возможно, но медленно. Я часто вызываю этот метод, потому что рисую диаграммы в пунктах «RecyclerView». 'instanceof' - это тяжелая операция, которую я должен выполнить для каждого типа диаграммы. И это не помогает мне с типом безопасности: я все еще могу передать любой метод «Просмотр», и мне все еще нужно «@SuppressWarnings (« unchecked »)». –

1

Написание аннотаций - хороший выбор, поскольку он не требует изменения исходного кода, он не налагает никаких накладных расходов во время выполнения, и он может дать вам гарантию времени компиляции, чтобы клиенты правильно использовали библиотеку.

Просто писать аннотации недостаточно. При компиляции вам также необходимо предоставить обработчик аннотации, который выдает ошибку компиляции, если вы неправильно используете аннотации. Таким образом, код, который вы показали, является хорошим началом, но отсутствует процессор аннотации.

Вы можете написать собственный обработчик аннотации или использовать существующий. То, что вы можете найти полезным, это Checker Framework. Кажется, хорошо подходит для вашего случая использования: вы можете использовать Subtyping Checker и компиляции кода с помощью команды, такие как

javac -processor org.checkerframework.common.subtyping.SubtypingChecker \ 
-Aquals=ChartView MyFile.java 
+0

Это действительно интересная информация, я об этом не знал. Я посмотрю. Спасибо. –