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()
:
A.equals(B)
implique B.equals(A)
(symétrie);A.equals(B)
et B.equals(C)
implique A.equals(C)
(transitivité);A.equals(B)
implique A.hashCode() == B.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:
STRICT
— Les objets comparés doivent être de la même classe
et tous leurs attributs strictement égaux, y compris d’éventuels attributs publics propres à l’implémentation.
BY_CONTRACT
— Les objets comparés doivent implémenter la même interface de GeoAPI (ou tout autre standard),
mais n’ont pas besoin d’être de la même classe d’implémentation. Seuls les attributs définis dans l’interface sont comparés;
tout autres attributs propres à l’implémentation — même s’ils sont publics — sont ignorés.
IGNORE_METADATA
— Comme BY_CONTRACT
,
mais ne compare que les attributs qui influencent les opérations (calculs numériques ou autre) effectuées par l’objet.
Par exemple dans un référentiel géodésique, la longitude (par rapport à Greenwich) du méridien d’origine sera pris en compte
alors que le nom de ce méridien sera ignoré.
APPROXIMATIVE
— Comme IGNORE_METADATA
,
mais tolère de légères différences dans les valeurs numériques.
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.