2009-12-06 2 views
7

Java: Как выполнять операции с разными определениями равными?Java: Как выполнять операции с разными определениями равных?

У меня есть два списка общих POJO. Мне нужно выполнить некоторые заданные операции в списках на основе разных способов сравнения POJO в списках.

Например, если мой POJO имел следующую структуру:

public class GenericPojo { 
    private String id; 
    private String address; 
    private String city; 
    private String country; 
    private String extraDetails; 
} 

(с соответствующими добытчиками и сеттеров)

Предоставлено List1<GenericPojo> и List2<GenericPojo>, как бы я найти:

List1 - List2 (где классы GenericPojo равны, если только идентификаторы равны)

Пересечение Лисы t1 и List2 (где id, address, city, country, но не extraDetails из GenericPojo равны)

бы два различных пользовательских классов компаратор быть полезны? Существуют ли библиотеки, которые эффективно обрабатывают эти операции или я должен попытаться реализовать свои собственные?

+0

Это мой первый вопрос, если я сделал какие-либо ошибки стиля или любые другие ошибки, пожалуйста, отредактируйте и сообщите мне, что я сделал неправильно. – 2009-12-06 12:53:09

+0

Обратите внимание, что текст можно форматировать как код, отступывая его как минимум в четырех пробелах. Вы также можете использовать кнопку кода («101 \ n010») в панели редактора для отступов. – outis

+0

Когда вы получаете перекресток, вам нужны два списка, поэтому представлены оба дополнительных элемента данных или один из двух достаточно? – Buhb

ответ

2

Если вы должны управлять классом вне своего контроля, я бы предложил использовать делегацию. Вот моя попытка:

  1. Создать RichList<T> обертку List с реализующими List контракт, основанный на decorator pattern.
  2. Создайте inteface EqualityChecker<T> с единственным методом `public boolean equal (T t1, T, t2).
  3. Внедрите этот интерфейс для своего общего pojo дважды: один проверяет только идентификатор, а другой проверяет другие поля.
  4. Добавьте оба метода, которые вас интересуют (установите подстановку и установите пересечение), но с дополнительным аргументом, который представляет собой конкретный экземпляр EqualityChecker<T>, который проведет для вас проверку равенства.

Таким образом, вы можете добавить обе операции ко всем существующим List с для любого вида объекта, для которого вы написали EqualityChecker.

Дальнейшие улучшения: Вы также можете написать по умолчаниюEqualityChecker<T> который просто вызывает метод Equals сравниваемых объектов. Затем вы можете перегрузить обе новые операции по умолчанию EqualityChecker.

1

Если в ваших списках нет дубликатов (с повторением к гипотетическим пользовательским классам компаратора), вы можете использовать два набора TreeSets, созданных с помощью двух ваших компараторов соответственно.

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

1

Учитывая ваши особые требования к равенству, List#removeAll() и List#retainAll() не подойдут вашим потребностям, поэтому я думаю, что вам понадобится специальная реализация, чтобы сделать что-то похожее на обе операции.

0

Нет решения, которое подчиняется контракту «Список», и ни одна из существующих реализаций списка не позволяет вам поставлять компаратор. Контракт «Список» определяет поведение списка в терминах метода каждого элемента equals(Object).

Предложение использования TreeSets с различными компараторами также является нарушением контракта, если метод compare компаратора несовместим с методом каждого элемента.

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

0

Если вы не хотите программировать заданные операции самостоятельно и вы не возражаете тратить несколько ресурсов процессора и памяти, вы можете:

  • конструкт WrappedPojo s на основе вашего GenericPojo s
  • дают WrappedPojo подходящих реализации equals()
  • создавать новые списки соответствующего вида WrappedPojo делать операцию на
  • скопируйте оставшиеся GenericPojo s обратно в исходные контейнеры (если необходимо) после завершения операции.

Уродливый, но простой.

0

Вы можете держать все это в предметной области с помощью следующего подхода:

  1. Реализовать equals( ... ) на GenericPojo основаны только на id.
  2. Определить WrappedPojo в качестве обертки вокруг GenericPojo с equals( ... ) на основе дополнительных полей GenericPojo.
  3. Для второго варианта использования используйте список обернутых экземпляров.

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

+0

Базовая POJO не одна, у меня есть контроль, возможно, решение оболочки более подходит для того, что я пытаюсь выполнить – 2009-12-06 13:39:43

0

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

Что вы делаете, выполняя операцию на проекции типа данных (то есть для суб набор полей)

Операции, которые вы используете также установлены операции, а не операции Списка. например вы не можете пересечь два списка (или, по крайней мере, вы должны определить, что это означает). Удалить может не выполнять точно так же, как вы ожидаете от списка.

Представьте, что у вас есть метод, который возвращает коллекцию pojos только с указанными вами полями. Я написал библиотеку, чтобы сделать это эффективно с динамически сгенерированным классом в прошлом, взглянуть на функциональную Java или аналогичную.

public static <Pojo, Pojo2> Set<Pojo2> project(Collection<Pojo> collection, 
     String... fieldsToRetain); 

List1 - List2 (где классы GenericPojo равны, если только идентификаторы равны)

Set<PojoWithId> setOfIds = project(list1, "id") 
setOfIds.retainAll(project(list2, "id")); 

Intersect из List1 и List2 (где идентификатор, адрес, город, страна, но не дополнительныеДетали по GenericPojo равны)

Set<PojoWithThreeFields> intersection = project(list1, "id", "address", "city", "country"); 
intersection.retainAll(project(list2, "id", "address", "city", "country")); 
Смежные вопросы