2010-05-04 4 views
4

ответа на этот вопрос, вероятно, «не представляется возможным», но позвольте мне спросить, независимо :)Перекрытия равно метод, не нарушая симметрию в классе, который имеет первичный ключ

Предполагая, что у нас есть очень простой класс, который имеет JAVA первичный ключ, например:

class Person { 
    String ssid; 
    String name; 
    String address; 
    ... 
} 

Теперь я хочу, чтобы сохранить людей в коллекции, то есть я должен переопределить метод Equals. Не совсем тривиальный, но на голой основе у меня будет что-то вдоль линий:

@Override 
public boolean equals (Object other) { 
    if(other==this) return true; 
    if(!other.getClass().equals(this.getClass()) return false; 
    Person otherPerson = (Person)other; 
    if(this.ssid.equals(otherPerson.getSsid()) return true; 
} 

Оправдания любых очевидных грубых ошибок, просто набрав это из головы. Теперь, скажем позже, в приложении у меня есть ssid, который я получил через пользовательский ввод. Если я хочу, чтобы сравнить свой SSID Лицу, я должен был бы назвать что-то вроде:

String mySsid = getFromSomewhere(); 
Person myPerson = getFromSomewhere(); 
if(myPerson.equals(new Person(mySsid)) doSomething(); 

Это означает, что я должен создать удобства конструктор для создания человека по беспроводной сети (если я уже нет один), и это также довольно многословно. Было бы гораздо лучше, чтобы просто позвонить

myPerson.equals(mySsid) 

но если я добавил сравнение строк к моей персоне равняется классу, что нарушило бы свойство симметрии, так как строка не получил понятия о том, как сравнивать себя персона.

Итак, большой вопрос, есть ли способ включить подобные «стенографические» сравнения с использованием метода overriden equals и без нарушения правила симметрии?

Спасибо за любые мысли!

РЕДАКТИРОВАТЬ: Это просто открытый вопрос, чем проблема, требующая точного решения. Уравнения должны учитывать случаи, когда я хочу извлечь Личность из коллекции. Так оно и должно быть возможно сделать что-то вроде этого:

List<Person> people = ... 
people.get(ssid); 

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

+1

Есть ли причина, по которой вы хотите это сделать? Не использовал бы что-то вроде 'myPerson.getSsid(). Equals (mySsid)' больше смысла, чем использование myPerson.equals (mySsid) '? – LukeH

+1

эта проблема обсуждается в Java Persistence with Hibernate, и я помню, что нет правильного способа ее выполнения. Авторы фактически рекомендуют использовать все, НО суррогатный ключ в сравнении в некоторых ситуациях, используя естественный ключ (или бизнес-ключ) в других, и сравнивая все значения в других, а также используя идентификатор в других. Я очень рекомендую обсуждение в этой книге. – les2

+0

Коста, все это тебе помогло? – Kylar

ответ

2

Вы не сравниваете два Person s, вы сравниваете два ssid s. Я хотел бы использовать:

myPerson.getSsid().equals(mySsid); 
+0

Верно, я полагаю, я должен был бы уточнить, что это должно относиться и к тому, чтобы люди также собирали коллекции. Так, например, people.get (ssid) должен идеально работать. – Kosta

+1

Почему вы не можете использовать SSID в качестве ключа на карте? Тогда вам не нужно беспокоиться о том, чтобы нарушить все эти правила симметрии. – Kylar

+0

@ Kosta: А теперь это делает вещи более интересными. Я подумаю об этом немного больше. –

3

Лучше всего, чтобы сохранить ваши люди в карте, то вы можете получить их легко:

HashMap<String, Person> people = new HashMap<String, Person>(); 

Person p = constructPersonFromStuff(); 

people.put(p.ssid, p); 

, а затем позже, вы можете увидеть, если человек существует:

String ssid = getFromSomewhere(); 

if(people.contains(ssid)){ 
    Person thatGuy = people.get(ssid); 
}else{ 
    //that person DOESN'T EXIST! HE'S A FIGMENT OF YOUR IMGAINATION! 
} 
+0

Я понимаю, что это не отвечает на ваш первоначальный вопрос, но похоже, это то, что вы пытаетесь в любом случае :) – Kylar

1

Нет смысла говорить, что Person равен строке, не спускайтесь по этому пути.

Я просто не понимаю вашу проблему. У вас есть этот код:

String mySsid = getFromSomewhere(); 
Person myPerson = getFromSomewhere(); 
if (myPerson.getSsid().equals(mySsid) doSomething(); 

Это не выглядит плохо для меня.Думаю, вы могли бы определить функцию, которая сделает это за вас:

if (myPerson.ssidEquals(mySsid)) doSomething(); 

Но это действительно не так уж важно.

В чем проблема?

1

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

Возможно, вы действительно хотите здесь, чтобы дать вашему Лину логический метод hasSsid(). Или просто позвоните myPerson.getSsid().equals(mySsid).

0

Метод equals никогда не должен возвращать true, если его аргумент не является экземпляром класса, на который был вызван метод.

, если хотите, вы можете создать интерфейс, например, идентифицируемый.

public interface Identifiable { 
    public Serializable getSsid(); 
} 

public class Person implements Identifiable { ... 

Вы можете затем написать свой код в общем виде с точки зрения идентификации ... это может помочь.

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

0

Вы можете создать структуру данных, пользовательские, который использует карту или набор внутренне:

public interface EntityStore<T,K> { 
    T get(K id); 
    boolean contains(Object o); 
    void put(K id, T entity); 
    void remove(Object o); 
    // ... 
} 

public class MapEntityStore<T,K> { 
    private Map<K,T> entities = new HashMap<K,T>(); 
    public T get(K id) { return entities.get(id); } 
    public boolean contains(Object o) { 
     if (entities.keySet().contains(o)) 
      return true; // search by id 
     if(entities.values().contains(o)) 
      return true; // search by value (this can be optimized if necessary) 

     return false; 
    } 
    ... 
} 

Вы можете использовать фабричный метод для создания экземпляров EntityStore, так что вы можете изменить оптимизированную/фантазию реализации по мере необходимости.