2017-01-17 5 views
0

Я знаю этот вопрос, как было задано столько времени, но в любом случае я не могу найти то, что могу применить к моему коду. Может быть, потому, что я не полностью понял все. Я просто хочу избежать решения @SuppressWarnings("unchecked"). Итак, найдите новую архитектуру для моего кода.Generics and unchecked cast

У меня есть предупреждение Unchecked cast:com.example.reader.models.SearchableBook to T на этой линии, когда я пытаюсь бросить в общий тип: (T)epubReader.readEpub(fileInputStream)

public class BookHelper { 
    public static <T> T openBook(String ebookFilePath, boolean searchable) { 
     T book = null; 
     EpubReader epubReader = new EpubReader(); 
     FileInputStream fileInputStream = null; 

     try { 
      fileInputStream = new FileInputStream(ebookFilePath); 
      book = searchable ? (T)new SearchableBook(epubReader.readEpub(fileInputStream)) : (T)epubReader.readEpub(fileInputStream); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       fileInputStream.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
     return book; 
    } 
} 

Я использую дженерики, потому что я хочу этот метод BookHelper может возвращать книги или SearchableBook избежать того, два очень похожих методы.

Я попытался отправить тип в качестве параметра методу, выполняя что-то подобное, но у меня все еще есть такое же предупреждение. Я до сих пор вернуть универсальный тип, так точно у меня такая же проблема:

public static <T> T openBook(String ebookFilePath, boolean searchable, Type t) { 
    T book = null; 
    EpubReader epubReader = new EpubReader(); 
    FileInputStream fileInputStream = null; 

    try { 
     fileInputStream = new FileInputStream(ebookFilePath); 
     if(t instanceof Book) { 
      book = (T)epubReader.readEpub(fileInputStream); 
     } else ... 

В этом последнем случае это не небезопасные вообще, так что я мог бы использовать SuppressWarnings, но я хотел бы сделать это правильный путь. .. и я хотел бы знать, как люди обычно делают в этом случае. Я думаю, лучший способ не повторить мой код, чтобы избежать этого предупреждения ...

Update 1

Теперь у меня есть свой интерфейс с возможностью поиска:

public interface Searchable { 

    String findSentence(String words); 
} 

обертка MyBook, который реализует этот интерфейс:

public class MyBook implements Searchable { 
    private Book mBook; 

    public MyBook(Book book) { 
     this.setBook(book); 
    } 

    public Book getBook() { 
     return mBook; 
    } 

    public void setBook(Book book) { 
     mBook = book; 
    } 

    @Override 
    public String findSentence(String words) { 
     return null; 
    } 
} 

Мой openBook(String ebookFilePath, boolean searchable) метод:

public static MyBook openBook(String ebookFilePath, boolean searchable) { 
    MyBook book = null; 
    EpubReader epubReader = new EpubReader(); 
    FileInputStream fileInputStream = null; 

    try { 
     fileInputStream = new FileInputStream(ebookFilePath); 
     book = new MyBook(epubReader.readEpub(fileInputStream)); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      fileInputStream.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    return book; 
} 

В MainActivity:

protected void onCreate(Bundle savedInstanceState) { 
... 
     MyBook searchBook = BookHelper.openBook(BOOK0_PATH, true); 
     Book book = BookHelper.openBook(BOOK1_PATH,false).getBook(); 
...  
} 

Он работает, без репликации коды, но. Если я хочу создать экземпляр книги, я просто создаю оболочку и вызываю getter getBook(). Но что случилось с ресурсами, используемыми для создания MyBook, которые мне не нужны для Book? Я говорю о ресурсе, используемом при реализации возможностей поиска =>findSentence(), которые относятся к поисковой книге (оболочка MyBook). Используются ли они только в моем методе OpenBook, и GC очистит их после? , На самом деле это выглядит так просто, что я не понимаю, почему я не думал об этом раньше ...

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

ответ

1

Что если вы определяете что-то вроде этого:

public static <T extends Book> T openBook(String ebookFilePath, boolean searchable)

Update:

Создать оболочку MyBook, которая включает в себя Book как поле.Затем создайте интерфейс Searchable и внесите его в MyBook. После этого вы можете удалить родовое:

public static MyBook openBook(String ebookFilePath, boolean searchable)

Создать геттер и сеттер для поля Book.

+0

Так что мой общий тип унаследует книгу. Как это должно работать? Я не могу использовать SearchableBook для T, если T расширяет книгу. – Laurent

+0

Ну, я думал, что 'SearchableBook' расширяет' Книгу' ... Если бы я не рекомендовал использовать интерфейс вместо родового типа. – beeb

+0

Итак, если я использую 'public static T openBook (String ebookFilePath, boolean searchable)' и 'SearchableBook' расширяет« Книгу », которая должна работать? – Laurent

0

сделать это проверенным исключением: void f() выбрасывает IllegalArgumentExceprion;

+0

'public static T openBook (String ebookFilePath, boolean searchable) бросает IllegalArgumentException {...}' все еще есть предупреждение. – Laurent

-1

Вы думали о создании интерфейса вместо использования дженериков? Таким образом, ваша книга или поисковик могут ее реализовать, и ваш бросок не будет проблемой.

Edit:

На самом деле нет никакой логики в использовании дженериков вообще, вы могли бы изменить дженерики интерфейс, как это: public interface BookBehaviour { Object readEpub(FileInputStream fileInputStream); } Тогда ваш класс SearchableBook должен реализовывать BookBehaviour, а также ваш метод readEpub (FileInputStream) должен возвращать типа BookBehaviour.

+0

Итак? если я хорошо понимаю, то у меня есть классы Book и SearchableBook, реализующие BookBehaviour. Тогда мне придется реализовать метод readEpub() для каждого класса, тогда мой код все еще реплицируется, не так ли? – Laurent

0

Я, наконец, изменил свою архитектуру.

Я хотел использовать этот класс Ebook от Epublib и добавить к нему возможность поиска в книге, чтобы найти предложение, содержащее конкретные слова, чтобы это было предназначено для моего класса SearchableBook.

import nl.siegmann.epublib.domain.Book; 

public class SearchableBook { 
    private Book mBook; 

    // Find a sentence containing the words in parameters 
    public Sentence findSentence(String[] wordsToFind) { ... } 

    ... 
} 

Сначала я пытался расширяет класс Epublib книги, но потом понял, что не может бросить книгу в SearchableBook и это было проблемой для меня в отношении моих планов. Поэтому я попробовал этот другой подход, который я объяснил в этой теме. Создание класса SearchableBook, который не проходит книги, но есть книги как свойство и класс BookHelper, чтобы избежать репликации этого:

EpubReader epubReader = new EpubReader(); 
FileInputStream fileInputStream = null; 

try { 
    fileInputStream = new FileInputStream(ebookFilePath); 
    book = epubReader.readEpub(fileInputStream); 
} catch (IOException e) { 
    e.printStackTrace(); 
} finally { 
    try { 
     fileInputStream.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

Чтобы иметь возможность использовать этот код для Book и SearchableBook класса я попытался (как описано в моем вопросе), чтобы сделать это в моем классе BookHelper:

public static <T> T openBook(String ebookFilePath, boolean searchable) throws IllegalArgumentException { 
     T book = null; 
     EpubReader epubReader = new EpubReader(); 
     FileInputStream fileInputStream = null; 

     try { 
      fileInputStream = new FileInputStream(ebookFilePath); 
      book = searchable ? (T)new SearchableBook(epubReader.readEpub(fileInputStream)) : (T)epubReader.readEpub(fileInputStream); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       fileInputStream.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
     return book; 
    } 

Но получил непроверенный бросок.

Затем я попытался использовать Interface:

public interface BookBehaviour { Object read(String ebookFilePath); } 

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

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

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

В любом случае, если у вас есть лучшее предложение, так что лучше ответьте на этот вопрос, пожалуйста.