Il n'y a aucune différence entre les objets; vous en avez un HashMap<String, Object>
dans les deux cas. Il y a une différence dans l' interface que vous avez avec l'objet. Dans le premier cas, l'interface est HashMap<String, Object>
, tandis que dans le second, c'est Map<String, Object>
. Mais l'objet sous-jacent est le même.
L'avantage de l'utilisation Map<String, Object>
est que vous pouvez changer l'objet sous-jacent en un autre type de carte sans rompre votre contrat avec le code qui l'utilise. Si vous le déclarez comme HashMap<String, Object>
, vous devez modifier votre contrat si vous souhaitez modifier l'implémentation sous-jacente.
Exemple: disons que j'écris cette classe:
class Foo {
private HashMap<String, Object> things;
private HashMap<String, Object> moreThings;
protected HashMap<String, Object> getThings() {
return this.things;
}
protected HashMap<String, Object> getMoreThings() {
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
La classe a quelques cartes internes de string-> object qu'elle partage (via des méthodes d'accesseur) avec des sous-classes. Disons que je l'écris avec HashMap
s pour commencer parce que je pense que c'est la structure appropriée à utiliser lors de l'écriture de la classe.
Plus tard, Mary écrit du code le sous-classant. Elle a quelque chose à faire avec les deux things
et moreThings
, donc naturellement, elle met cela dans une méthode commune, et elle utilise le même type que j'ai utilisé sur getThings
/ getMoreThings
lors de la définition de sa méthode:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
Plus tard, je décide qu'en fait, c'est mieux si j'utilise à la TreeMap
place de HashMap
in Foo
. Je mets à jour Foo
, en changeant HashMap
pour TreeMap
. Maintenant, SpecialFoo
ne compile plus, parce que j'ai rompu le contrat: je Foo
disais qu'il fournissait des HashMap
s, mais maintenant il fournit à la TreeMaps
place. Nous devons donc corriger SpecialFoo
maintenant (et ce genre de chose peut se répercuter sur une base de code).
À moins d'avoir une très bonne raison de partager que mon implémentation utilisait un HashMap
(et cela se produit), ce que j'aurais dû faire était de déclarer getThings
et getMoreThings
de simplement revenir Map<String, Object>
sans être plus précis que cela. En fait, sauf une bonne raison de faire autre chose, même à l'intérieur, Foo
je devrais probablement déclarer things
et moreThings
comme Map
, non HashMap
/ TreeMap
:
class Foo {
private Map<String, Object> things; // <== Changed
private Map<String, Object> moreThings; // <== Changed
protected Map<String, Object> getThings() { // <== Changed
return this.things;
}
protected Map<String, Object> getMoreThings() { // <== Changed
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Notez comment j'utilise maintenant Map<String, Object>
partout où je peux, en n'étant spécifique que lorsque je crée les objets réels.
Si j'avais fait ça, alors Mary aurait fait ça:
class SpecialFoo extends Foo {
private void doSomething(Map<String, Object> t) { // <== Changed
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
... et changer Foo
n'aurait pas fait SpecialFoo
arrêter la compilation.
Les interfaces (et les classes de base) nous permettent de révéler tout ce qui est nécessaire , en gardant notre flexibilité sous les couvertures pour apporter les modifications appropriées. En général, nous voulons que nos références soient aussi simples que possible. Si nous n'avons pas besoin de savoir que c'est un HashMap
, appelez-le simplement a Map
.
Ce n'est pas une règle aveugle, mais en général, le codage vers l'interface la plus générale sera moins fragile que le codage vers quelque chose de plus spécifique. Si je m'en étais souvenu, je n'aurais pas créé un Foo
qui aurait mis Mary en échec SpecialFoo
. Si Mary s'était souvenue de cela, alors même si j'avais gâché Foo
, elle aurait déclaré sa méthode privée avec Map
au lieu de HashMap
et mon Foo
contrat de changement n'aurait pas eu d'impact sur son code.
Parfois, vous ne pouvez pas faire cela, parfois vous devez être précis. Mais à moins que vous n'ayez une raison de l'être, optez pour l'interface la moins spécifique.