nous avons une classe Book comme celle-ci:
public class BookList extends ArrayList<Book> {
BookList searchBookByName(String name) {
BookList matchedBooks = new BookList();
for (Book book : this) {
if (book.name.equals(name)) {
matchedBooks.add(book);
}
}
return matchedBooks;
}
}
et la classe BookList étend Arraylist:
public class Book {
String name, isbn, author, publisher;
int publishedYear, price;
}
Si vous souhaitez en plus écrire des méthodes searchBookByXXX avec un champ de recherche différent, il y a quatre champs de chaîne et je pense que l'implémentation de la méthode sera la même que la méthode searchBookByName.
Ce serait certainement la violation du principe sec.
Dans ce cas, est-il souhaitable d'utiliser la réflexion Java? ou existe-t-il une autre solution?
3 Réponses :
La réflexion ne serait pas le choix idéal. En règle générale, vous ne devez utiliser la réflexion que si cela est absolument nécessaire. La meilleure option serait de créer une méthode plus générale que les autres méthodes délèguent à:
public BookList searchBookBy(java.util.function.Predicate<? super Book> filter) {
return stream().filter(filter).collect(Collectors.toCollection(BookList::new));
}
Si vous souhaitez utiliser des flux, la méthode searchBookBy peut être modifiée en :
public BookList searchBookBy(java.util.function.Predicate<? super Book> filter) {
BookList matchedBooks = new BookList();
for (Book book : this) {
if (filter.test(book)) {
matchedBooks.add(book);
}
}
return matchedBooks;
}
public BookList searchBookByName(String name) {
return searchBookBy(book -> book.getName().equals(name));
}
Essayez ceci.
<T> BookList search(T key, Function<Book, T> getter) {
return stream()
.filter(book -> getter.apply(book).equals(key))
.collect(Collectors.toCollection(BookList::new));
}
BookList searchBookByName(String key) { return search(key, book -> book.name); }
BookList searchBookByIsbn(String key) { return search(key, book -> book.isbn); }
BookList searchBookByAuthor(String key) { return search(key, book -> book.author); }
BookList searchBookByPublisher(String key) { return search(key, book -> book.publisher); }
BookList searchBookByPublishedYear(int key) { return search(key, book -> book.publishedYear); }
BookList searchBookByPrice(int key) { return search(key, book -> book.price); }
Ce serait une solution alternative. Merci!
1+, mais je pense que l'utilisation d'un Prédicat facilite la compréhension par rapport au passage d'une Fonction (et d'une clé).
Je pense que la réflexion serait un choix terrible.
Vous avez eu une méthode suggérant une classe de filtre. Une autre possibilité serait de définir une énumération dans votre classe, accessible par les appelants, à passer à une méthode find pour indiquer le champ sur lequel rechercher. Le filtre est plus général, les énumérations sont peut-être plus faciles à comprendre.
EDIT:
J'ai jeté ceci ensemble très rapidement; Je ne l'ai même pas compilé, c'est juste pour l'illustration. Désolé, c'est l'heure du coucher où je suis ...
public class Booklist
{
public enum FieldType { NAME, ISBN, AUTHOR, PUBLISHER, PUBLISHED_YEAR, PRICE };
private HashMap<FieldType, BookFilter> fieldTypeFilters;
static
{
fieldTypeFilters.put(NAME, new NameFilter);
fieldTypeFilters.put(ISBN, new IsbnFilter);
fieldTypeFilters.put(AUTHOR, new AuthorFilter);
fieldTypeFilters.put(PUBLISHER, new PublisherFilter);
fieldTypeFilters.put(PUBLISHED_YEAR, new PublishedYearFilter);
fieldTypeFilters.put(PRICE, new PriceFilter);
}
BookList searchBooks(FieldType fieldType, Object value)
{
BookFilter filter = fieldTypeFilters.get(fieldType);
BookList matchedBooks = search(value, filter);
}
private class NameFilter
{
public boolean test(Book book, Object targetName)
{
return book.getName().equals(targetName.toString());
}
}
}
J'ai pu affiner la solution d'énumération au sélénium. Je pense que c'est la solution la plus compréhensible.
Et il n'y a aucune raison pour laquelle vous ne pouvez pas avoir d'énumérations pour le cas de recherche d'un seul champ et de filtres pour un cas plus général. Vous pouvez définir des filtres (classe interne?) Pour chaque cas à champ unique, et les appels enum peuvent obtenir le filtre correct avec une carte, puis appeler la version du filtre.
pourquoi serait-ce un choix terrible d'utiliser la réflexion? Je pense que dans une opération findBy ... où le goulot d'étranglement est la base de données, le temps de réflexion devrait être négligeable. Cependant, je ne suis pas sûr que vous puissiez faire quelque chose d'aussi dynamique en Java. Parce que pendant la compilation, il a besoin de savoir que la méthode est là. Je ne sais pas comment contourner cela.
Pouvez-vous donner un exemple de l'approche enum? Je me demande comment il pourrait être plus lisible tout en maintenant la sécurité des types.
@AminM Reflection est moins lisible et vous perdez toute sécurité de type à la compilation. N'utilisez la réflexion que s'il n'y a pas d'autre choix (ou si l'alternative serait significativement plus de travail à implémenter / maintenir).
@Slaw assez juste
Bonne solution. En variante, chaque nouvel objet … Filter pourrait être passé au constructeur de l'énumération et enregistré en tant que champ membre de l'énumération.