2013-06-08 10 views
17

Supponiamo Ho classe User:È corretto per equals() dipendere solo da un ID?

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

E 'proprio l'override del metodo equals come segue?

@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; 
} 

Si scopre che l'unicità di un oggetto è determinata solo dal suo ID. Ma nella mia applicazione, id è sempre univoco. È fornito nel database. La mia implementazione equals è sufficientemente competente per tener conto di ciò? O non è questa la migliore pratica?

Naturalmente capisco che in questo caso l'attuazione hashCode dovrebbe essere la seguente:

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

A cosa serve '.equals()', se mai? – fge

+0

Sembra che tu stia bene. Se l'oggetto è uguale quando gli ID sono uguali, hai il codice corretto. – greedybuddha

+2

Prima che un 'utente' venga mantenuto,' id' può essere nullo, e quindi 'equals' getterà. Ma questa è solo una verruca. Ho visto il tuo modello spesso. Una domanda su SO ha portato a questo frammento di documentazione di Hibernate, che potrebbe non avere importanza per te: http://docs.jboss.org/hibernate/core/4.0/manual/en-US/html/persistent-classes.html#persistent- classes-equalshashcode –

risposta

0

Va bene. Fintanto che due utenti diversi non possono avere lo stesso ID, la tua funzione equals è sufficiente. Ci potrebbe essere un problema se un utente può essere rappresentato due volte con un ID diverso (per qualsiasi motivo) e si vuole considerarli uguali.

0

tuoi equals() Metodo dosen't guardare come è stato generato da IDE in quanto non controlla 'id' valore nullo come dichiarato da @Eric ..

questo è ciò che i miei equals()/metodo hashCode() sembrava utilizzando stesso ID 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; 
} 

dovremmo sempre utilizzare la generazione automatica di codice standard dove possibile, in quanto è molto meno soggetto ad errori.

inoltre, per quanto riguarda il tuo punto riguardante l'unicità del puntello "id", che dipende dalle tue preferenze e da come vuoi utilizzare il metodo equals (requisiti aziendali) cioè se il nome di due utenti è lo stesso devono essere considerati uguali quando si confrontano due oggetti utente più avanti ..

4

Se si dovrebbe fare questo dipende dalla semantica della classe. Cioè, che cosa significa significa dire che due oggetti della tua classe sono equivalenti? La distinzione più importante è tra oggetti con semantica del valore e oggetti con semantica delle entità. Gli oggetti entità non sono equivalenti anche se hanno attributi equivalenti (colore, lunghezza, ecc.). In molti casi, anche quando l'oggetto è stato letto da una tabella di database che ha una chiave primaria, gli oggetti entità avranno un campo ID univoco. Confrontare solo il campo ID in quel caso è la cosa giusta da fare.

+0

Se un oggetto' User' rappresenta le caratteristiche di qualche utente in un database, dovrebbe essere possibile che più di un tale oggetto esista contemporaneamente per ogni dato ID? Sembrerebbe che per coerenza sarebbe meglio avere tutti questi oggetti costruiti con un metodo factory che usa una sorta di collezione con riferimenti deboli per garantire che finché esiste un riferimento a un utente con qualche ID, qualsiasi richiesta ottenere un 'utente' con quell'ID restituirà lo stesso oggetto. Se ciò è fatto, non ci sarà bisogno di 'User' per sovrascrivere' equals'. – supercat

0

È corretto utilizzare l'id per il metodo equals a condizione che non sia necessario confrontare un'entità che non è stata ancora salvata nel DB. Se vuoi confrontare entità che non sono state ancora salvate, dovrai confrontare i loro attributi.

0

Sono d'accordo che è sull'id. Ma ho avuto problemi nel ricevere dati che dovrebbero aggiornare il database. Con questo esempio con Utente a cui è uguale solo l'ID, l'ho creato.

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; 
    } 
} 

Con questo possiamo avere questo.

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); 
     } 
    } 
} 
} 

allora possiamo fare questo

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

Siete d'accordo che questo è un modo per fare questo. ??????