2013-06-08 11 views
17

Załóżmy mam klasę User:Czy właściwe jest, aby equals() zależało tylko od identyfikatora?

public class User { 
    private Long id; 
    private String name; 
    private Integer age; 
    private BigDecimal account; 
    // other fields, getters and setters 
} 

Czy to wypada zastąpić metodę equals następująco?

@Override 
public boolean equals(Object ob) { 
    if (ob == null) { 
     return false; 
    } 
    if (this == ob) { 
     return true; 
    } 
    if (ob instanceof User) { 
     User other = (User) ob; 
     return this.id.equals(other.getId()); 
    } 
    return false; 
} 

Okazuje się, że wyjątkowość obiektu jest określona tylko jego identyfikatorem. Ale w mojej aplikacji, id jest zawsze wyjątkowy. Jest dostarczany w bazie danych. Czy moja implementacja equals jest na tyle kompetentna, aby to uwzględnić? Czy nie jest to najlepsza praktyka?

Oczywiście rozumiem, że w tym przypadku realizacja hashCode powinny być następujące:

@Override 
public int hashCode() { 
    return id.intValue(); 
} 
+2

Czego potrzebujesz '.equals()' dla, jeśli w ogóle coś? – fge

+0

Wygląda na to, że jesteś dobry. Jeśli obiekt jest równy, gdy id są równe, masz poprawny kod. – greedybuddha

+2

Zanim "Użytkownik" zostanie utrwalony, "id" może mieć wartość null, a następnie "równy" wyrzuci. Ale to tylko brodawka. Widziałem często twój wzorzec. Jedno pytanie SO doprowadziło do tego fragmentu dokumentacji Hibernate, która może nie mieć znaczenia dla Ciebie: http://docs.jboss.org/hibernate/core/4.0/manual/en-US/html/persistent-classes.html#persistent- classes-equalshashcode –

Odpowiedz

0

Jest w porządku. Dopóki dwóch różnych użytkowników nie może mieć tego samego identyfikatora, wystarczy funkcja equals. Może wystąpić problem, jeśli jeden użytkownik może być reprezentowany dwukrotnie z innym identyfikatorem (bez względu na przyczynę) i chcesz uznać je za równe.

0

wam równi() metoda nie robi wyglądać jak to zostało wygenerowane przez IDE, ponieważ nie sprawdza „id” wartości zerowej jak stwierdził @Eric ..

to co moi equals()/metoda hashCode() wyglądało przy użyciu tego samego identyfikatora prop

@Override 
public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + ((id == null) ? 0 : id.hashCode()); 
    return result; 
} 

@Override 
public boolean equals(Object obj) { 
    if (this == obj) 
     return true; 
    if (obj == null) 
     return false; 
    if (getClass() != obj.getClass()) 
     return false; 
    User11 other = (User11) obj; 
    if (id == null) { 
     if (other.id != null) 
      return false; 
    } else if (!id.equals(other.id)) 
     return false; 
    return true; 
} 

powinniśmy zawsze używać automatycznego generowania kodu boilerplate gdzie to możliwe, ponieważ jest o wiele mniej podatny na błędy.

również, jeśli chodzi o twój punkt dotyczący unikalności "id" prop, który zależy od twoich preferencji i sposobu, w jaki chcesz użyć ciebie równa się (wymaganie biznesowe), tj. Jeśli dwa nazwiska użytkownika są takie same, to powinny być uważane za takie same przy porównywaniu dwa obiekty użytkownika później ..

4

To, czy powinieneś to zrobić, zależy od semantyki twojej klasy. To znaczy, co oznacza, że ​​dwa obiekty twojej klasy są równoważne? Najważniejsze rozróżnienie dotyczy obiektów z semantyką wartości i obiektów z semantyką encji. Obiekty encji nie są równoważne, nawet jeśli mają równoważne atrybuty (kolor, długość itp.). W wielu przypadkach, w tym gdy obiekt został odczytany z tabeli bazy danych, która ma klucz podstawowy, obiekty obiektu będą miały jedno unikalne pole ID. Porównywanie tylko pola ID w tym przypadku jest słuszne.

+0

Jeśli obiekt' User' reprezentuje cechy niektórych użytkowników w baza danych, czy istnieje możliwość istnienia więcej niż jednego takiego obiektu jednocześnie dla dowolnego identyfikatora? Wydaje się, że dla zachowania spójności lepiej byłoby, gdyby wszystkie takie obiekty były konstruowane za pomocą metody fabrycznej, która używa jakiegoś zbioru odwołującego się do słabych referencji, aby zapewnić, że tak długo jak jakiekolwiek odniesienie istnieje do "użytkownika" z jakimś identyfikatorem, wszelkie żądania uzyskanie "użytkownika" z tym identyfikatorem zwróci ten sam obiekt. Jeśli tak się stanie, nie będzie potrzeby, aby 'Użytkownik' zastępował' równy'. – supercat

0

Można używać id dla metody equals, o ile nie trzeba porównywać jednostki, która nie była jeszcze przechowywana w bazie danych. Jeśli chcesz porównać jednostki, które nie zostały jeszcze zapisane, musisz porównać ich atrybuty.

0

Zgadzam się, że jest na identyfikatorze. Ale miałem problemy z uzyskaniem danych, które powinny zaktualizować bazę danych. W tym przykładzie z użytkownikiem, w którym równy jest tylko identyfikator, utworzyłem go.

interface DataEquals<T extends DataEquals> { 
    public boolean isDataEquals(T other) 
} 


User implements DataEquals<User> { 
    public boolean isDataEquals(User other) { 
     boolean b1 = getName().equals(other.getName()); 
     boolean b2 = getAge().equals(other.getAge()); 
     boolean b3 = getAccount().equals(other.getAccount()); 
     return b1 && b2 && b3; 
    } 
} 

Dzięki temu możemy mieć to.

public class ListChanges<T extends DataEquals<T>> { 

    private List<T> added = new ArrayList<T>(); 
    private List<T> removed = new ArrayList<T>(); 
    private List<T> changed = new ArrayList<T>(); 
    private List<T> unchanged = new ArrayList<T>(); 

    public ListChanges() { 
    super(); 
    } 
    public List<T> getAdded() { 
    return added; 
    } 
    public List<T> getChanged() { 
    return changed; 
    } 
    public List<T> getRemoved() { 
    return removed; 
    } 
    public List<T> getUnchanged() { 
    return unchanged; 
    } 

    public boolean hasAnyChanges() { 
    return added.size()>0 || removed.size()>0 || changed.size()>0; 
    } 

    public void parse(List<T> oldList,List<T> newList) { 
    for (T oldObj : oldList) { 
     int index =newList.indexOf(oldObj); 
     if (index==-1) { 
      removed.add(oldObj); 
     } else { 
      T newObj = newList.get(index); 

      if (newObj.isDataEquals(oldObj)) { 
       unchanged.add(oldObj); 
      } else { 
       changed.add(newObj); 
      } 
     } 
    } 
    for (T newObj : newList) { 
     if (oldList.indexOf(newObj)==-1) { 
      added.add(newObj); 
     } 
    } 
} 
} 

Wtedy możemy zrobić to

List<User> oldList = ....; 
List<User> newList = ...; 
ListChanges<User> listChanges = new ListChanges<User>(); 
listChanges.parseChanges(oldList,newList); 

Czy zgadzasz to jest sposób, aby to zrobić. ??????