Эффективный способ сортировки списка на основе нескольких свойств с помощью Google Guava

Я использую Google Guava 17.0 библиотеку. У меня есть класс с именем AroundBust, содержащий только два свойства id типа Integer и size типа BigDecimal.

Этот класс создается на основе данных, хранящихся в файле XML. A java.util.List заполняется списком объектов этого класса.

Этот список отображается в таблице данных PrimeFaces .

Этот список сортируется на основе заказов сортировки, предоставленных таблицей данных (множественная сортировка).

Я пытаюсь сортировать список следующим образом (в связанном компоненте JSF).

@ManagedBean
@ViewScoped
public final class AroundBustManagedBean extends LazyDataModel<AroundBust> implements Serializable {

    private List<AroundBust> entireList;
    private static final long serialVersionUID = 1L;

    private static final class IntegerSorting {

        private IntegerSorting() {}

        public static Function<AroundBust, Integer> getInstance() {
            return Holder.INSTANCE;
        }

        private enum Holder implements Function<AroundBust, Integer> {

            INSTANCE {
                @Override
                public Integer apply(AroundBust f) {
                    return f.getId();
                }
            }
        }
    }

    private static final class BigDecimalSorting {

        private BigDecimalSorting() {}

        public static Function<AroundBust, BigDecimal> getInstance() {
            return Holder.INSTANCE;
        }

        private enum Holder implements Function<AroundBust, BigDecimal> {

            INSTANCE {
                @Override
                public BigDecimal apply(AroundBust f) {
                    return f.getSize();
                }
            }
        }
    }

    @Override
    public List<AroundBust> load(int first, int pageSize, List<SortMeta> multiSortMeta, final Map<String, Object> filters) {
        //The instance variable entireList is populated by unmarshalling the XML file in question.
        int listSize = 0;

        Map<String, String> map = null;
        //Assuming the List parameter multiSortMeta is somehow turned into a map.
        //I'm not presenting it here to reduce the code complexity.

        //The sorting is performed by the code below using the Guava library.
        if (map != null && !map.isEmpty()) {
            Ordering<AroundBust> id = null;
            Ordering<AroundBust> value = null;
            Ordering<AroundBust> idValue = null;
            Ordering<AroundBust> valueId = null;

            for (Map.Entry<String, String> entry : map.entrySet()) {
                if (entry.getKey().equalsIgnoreCase("id")) {
                    id = entry.getValue().equalsIgnoreCase("asc") ? Ordering.natural().onResultOf(IntegerSorting.getInstance()) : Ordering.natural().onResultOf(IntegerSorting.getInstance()).reverse();

                    if (value != null) {
                        valueId = value.compound(id);
                    }
                } else if (entry.getKey().equalsIgnoreCase("size")) {
                    value = entry.getValue().equalsIgnoreCase("asc") ? Ordering.natural().onResultOf(BigDecimalSorting.getInstance()) : Ordering.natural().onResultOf(BigDecimalSorting.getInstance()).reverse();

                    if (id != null) {
                        idValue = id.compound(value);
                    }
                }
            }

            if (idValue != null) {
                entireList = idValue.sortedCopy(entireList);
            } else if (valueId != null) {
                entireList = valueId.sortedCopy(entireList);
            } else if (id != null) {
                entireList = id.sortedCopy(entireList);
            } else if (value != null) {
                entireList = value.sortedCopy(entireList);
            }
        } else {
            //This is just a default sort order, when the data table is loaded for the first time.
            entireList = Ordering.natural().onResultOf(IntegerSorting.getInstance()).reverse().sortedCopy(entireList);
        }

        return new ArrayList<AroundBust>(entireList.subList(first, Math.min(pageSize + first, listSize)));
    }
}

Карта поддерживает список полей для сортировки с именем поля в качестве ключа и порядка сортировки («asc» для возрастания и «desc» для убывающего порядка) как его значение в точном порядке, в котором данные заголовок столбца таблицы.

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

Эти условные проверки значительно увеличиваются по мере увеличения числа свойств /полей в классе. В результате код может быть неуправляемым позже.

Как уменьшить этот код в минимальной степени?

11 голосов | спросил Tiny 1 J000000Tuesday14 2014, 15:46:03

1 ответ


11

Запах кода: вы делаете одно и то же снова и снова, с разными экземплярами одного и того же типа переменных.

            if(idValue!=null) {
                entireList=idValue.sortedCopy(entireList);
            } else if(valueId!=null) {
                entireList=valueId.sortedCopy(entireList);
            }else if(id!=null) {
                entireList=id.sortedCopy(entireList);
            }else if(value!=null) {
                entireList=value.sortedCopy(entireList);
            }

Вместо этого назначьте правильное значение для этого типа новой переменной, а затем используйте его один раз.

            Ordering<AroundBust> selectedOrdering = createOrdering(map);
            entireList = selectedOrdering.sortedCopy(entireList);

Запах кода: не повторяйте себя

value = entry.getValue().equalsIgnoreCase("asc")?Ordering.natural().onResultOf(BigDecimalSorting.getInstance()):Ordering.natural().onResultOf(BigDecimalSorting.getInstance()).reverse();

Здесь ключ сообщает вам, что вы хотите сортировать BigDecimal, а значение указывает вам, следует ли его отменить.

Ordering<AroundBust> selectedOrdering = Ordering.natural().onResultOf(BigDecimalSorting.getInstance());
if (entry.getValue().equalsIgnoreCase("asc")) {
    selectedOrdering = selectedOrdering.reverse();
}

У вас такая же проблема:

    else {
        //This is just a default sort order, when the data table is loaded for the first time.
        entireList=Ordering.natural().onResultOf(IntegerSorting.getInstance()).reverse().sortedCopy(entireList);
    }

Еще раз, вы на самом деле ничего не делаете - вы создаете Ordering, а затем используете его для sortedCopy списка. Поэтому ваш код действительно хочет выглядеть как

Ordering<AroundBust> selectedOrdering = Ordering.natural().onResultOf(IntegerSorting.getInstance()).reverse();

if(map!=null&&!map.isEmpty())
{
    selectedOrdering = this.createOrdering(map);
}

entireList = selectedOrdering.sortedCopy(entireList);

Перечисления держателя в ваших функциях сортировки на самом деле не дают вам ничего здесь. Если вы не заимствуете этот код из другого места, он должен иметь возможность напрямую использовать перечисление.

    private enum BigDecimalSorting implements Function<AroundBust, BigDecimal> {
        INSTANCE {
            public BigDecimal apply(AroundBust f) {
                return f.getSize();
            }
        }
    }

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

private static final Function<AroundBust,BigDecimal> GET_SIZE = new Function<AroundBust, BigDecimal>() {
    public BigDecimal apply(codeReview.sortingAList.AroundBust f) {
        return f.getSize();
    }
};

Логика выбора возвращаемых записей должна быть очищена бит

return new ArrayList<AroundBust>(entireList.subList(first, Math.min(pageSize + first, listSize)));

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

int last = Math.min(pageSize + first, listSize);
List<AroundBust> page = Lists.newArrayList(entireList.subList(first,last));
return page;

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

ответил VoiceOfUnreason 1 J000000Tuesday14 2014, 17:28:01

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132