Modes de comparaisons des objets

Il existe différentes opinions sur la façon d’implémenter la méthode Object.equals(Object) du Java standard. Selon certains, il doit être possible de comparer différentes implémentations d’une même interface ou classe de base. Mais cette politique nécessite que chaque interface ou classe de base définisse entièrement dans sa Javadoc les critères ou calculs que doivent employer les méthodes equals(Object) et hashCode() dans toutes les implémentations. Cette approche est choisie notamment par java.util.Collection et ses interfaces filles. La transposition de cette approche aux centaines d’interfaces de GeoAPI serait toutefois une entreprise ardue, qui risquerait d’être assez peu suivie par les diverses implémentations. En outre, elle se fait au détriment de la possibilité de prendre en compte des attributs supplémentaires dans les interfaces filles si cette possibilité n’a pas été spécifiée dans l’interface parente. Cette contrainte découle des points suivants du contrat des méthodes equals(Object) et hashCode():

Par exemple ces trois contraintes sont violées si A (et éventuellement C) peuvent contenir des attributs que B ignore. Pour contourner cette difficulté, une approche alternative consiste à exiger que les objets comparés par la méthode Object.equals(Object) soient exactement de la même classe, c’est-à-dire que A.getClass() == B.getClass(). Cette approche est parfois considérée contraire aux principes de la programmation orientée objets. Dans la pratique, pour des applications relativement complexes, l’importance accordée à ces principes dépend du contexte dans lequel les objets sont comparés: si les objets sont ajoutés à un HashSet ou utilisés comme clés dans un HashMap, alors nous avons besoin d’un strict respect du contrat de equals(Object) et hashCode(). Mais si le développeur compare les objets lui-même, par exemple pour vérifier si des informations qui l’intéresse ont changées, alors les contraintes de symétrie, transitivité ou de cohérence avec les valeurs de hachages peuvent ne pas être pertinentes pour lui. Des comparaisons plus permissives peuvent être souhaitables, allant parfois jusqu’à tolérer de légers écarts dans les valeurs numériques.

Afin de donner une certaine flexibilité aux développeurs, un grand nombre de classes de la bibliothèque SIS implémentent l’interface org.apache.sis.util.LenientComparable, qui défini une méthode equals(Object, ComparisonMode). Les principaux modes de comparaisons sont:

Le mode par défaut, utilisé par les toutes les méthodes equals(Object) de SIS, est STRICT. Ce mode est choisi pour une utilisation sécuritaire — notamment avec HashMap — sans nécessiter de définitions rigoureuses des méthodes equals(Object) et hashCode() dans toutes les interfaces. Avec ce mode, l’ordre des objets (A.equals(B) ou B.equals(A)) n’a pas d’importance. C’est toutefois le seul mode à offrir cette garantie. Dans l’expression A.equals(B), le mode BY_CONTRACT (et donc par extension tous les autres modes qui en dépendent) ne comparera que les propriétés connues de A, sans se soucier de savoir si B en connaît davantage.