2009-09-30 5 views
1

У меня есть приложение Java, которое использует JPA.Как лучше всего обращаться Список <Entity>, Список <Entity Id>, Список <Entity name> эффективно?

Скажем, у меня есть объект под названием Product с name и price атрибутов (все объекты имеют атрибут id).

Естественно, я могу получить List<Product> довольно легко (из запроса или другого объекта), но часто я хочу List<String> (список названий продуктов) или List<Long> (список цен на продукцию или список идентификаторов продукта).

Много времени это так же легко пройти весь Product вокруг, но есть два случая, когда я не хочу, чтобы это сделать:

  • Я передаю список в классе который не должен зависеть от класса Product.
  • Значительно проще/быстрее получить список идентификаторов, чем полные объекты продукта (но в некоторых случаях у меня уже есть).

Наивный способ сделать это бы что-то вроде:

List<Long> productIds = new ArrayList<Long>(); 
for(Product product: products) { 
    productIds.add(product.getId()); 
} 

Но мне не нравится это, потому что это грязно и неэффективно. В Python я хотел бы сделать что-то вроде:

[ p.id for p in products ] 

"Лучший" Я могу придумать в Java является:

public class ProductIdList extends AbstractList<Long> { 
    private List<Product> data; 

    public ProductIdList(List<Product> data) { 
    this.data = data; 
    } 

    public Long get(int i) { 
    return data.get(i).getId(); 
    } 

    public int size() { 
    return data.size(); 
    } 

    public Long remove(int i) { 
    return data.remove(i).getId(); 
    } 

    /* For better performance */ 
    public void clear() { 
    data.clear(); 
    } 

    /* Other operations unsupported */ 
} 

Плюсы:

  • Этот подход не нужно скопируйте данные
  • Это истинный «вид» на данные - отражаются изменения в базовом списке.

Минусы:

  • Кажется, что много кода
  • нужен класс, как это для каждого атрибута Я хочу, чтобы получить доступ, как этот

Так это хорошо идея или нет? Должен ли я просто создавать вторичные списки большую часть времени? Есть ли третий вариант, который я не рассматривал?

+0

Положив комментарий не ответ. Просто небольшой совет, вы всегда можете получить только идентификаторы продукта, а не весь продукт (используя то, что я слышал, называемый скалярным запросом). Например. SELECT prod.id FROM Product prod ... –

+0

Точно. Возможно, я должен был быть яснее. Иногда я могу это сделать, и проблем нет. Иногда у меня уже есть Список и не хочу требовать. – Draemon

+0

Вы можете использовать один класс, который имеет один метод для каждого атрибута. Это уменьшило бы одну CONS. – StampedeXV

ответ

1

Вы можете уменьшить размер этих классов за атрибуте оберток, имея их наследуются от абстрактного класса, который имеет метод GetAttribute.Что-то вроде этого:

public abstract class AbstractProductList<T> extends AbstractList<T> { 
    protected List<Product> data; 

    public AbstractProductList(List<Product> data) { 
    this.data = data; 
    } 

    protected abstract T getAttribute(Product product); 

    public T get(int i) { 
    return getAttribute(data.get(i)); 
    } 

    public int size() { 
    return data.size(); 
    } 

    public T remove(int i) { 
    return getAttribute(data.remove(i)); 
    } 

    /* For better performance */ 
    public void clear() { 
    data.clear(); 
    } 

    /* Other operations unsupported */ 
} 

public class ProductIdList extends AbstractProductList<Long> { 
    public ProductIdList(List<Product> data) { 
    super(data); 
    } 

    protected Long getAttribute(Product product) { 
    return product.getId(); 
    } 
} 
+0

Мне это нравится. Я думаю, что класс Product также может стать общим. – Draemon

0

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

Это ваш пример, настроенный с моим предложением.

public class ProductList { 
    private List<Product> data; 

    public ProductIdList(List<Product> data) { 
    this.data = data; 
    } 

    public Long getId(int i) { 
    return data.get(i).getId(); 
    } 

    public List<String> getProductNames(int i) { 
    return data.get(i).getProductNames(); 
    } 

    public Product getProduct(int i) { 
    return data.get(i); 
    } 

    public int size() { 
    return data.size(); 
    } 

    public Long remove(int i) { 
    return data.remove(i).getId(); 
    } 

    /* For better performance */ 
    public void clear() { 
    data.clear(); 
    } 
} 
+0

Это не реализует List, поэтому его нельзя использовать там, где ожидается список . – Draemon

3

Просто бросить в другой возможности, вы можете использовать трансформатор Apache Commons' и собирать, чтобы создать новую коллекцию или преобразования, чтобы изменить существующий:

Collection<Long> productIds = CollectionUtils.collect(products, new Transformer() { 
     public Long transform(Object o) { 
      return ((Product) o).id; 
     } 
    }); 
+0

Это, вероятно, самый правильный способ реализовать именно то, что я хочу. К сожалению, Commons не догнал дженерики, так что и дополнительная библиотека означает, что я не могу это оправдать. Тем не менее, +1 – Draemon

Смежные вопросы