J'ai un type générique relativement compliqué (Dites hier, j'ai redécouvert l'idiome suivant et j'ai été déçu d'apprendre que c'est Carte
class MyClass
{
/* "Pseudo typedef" */
private static class FooBarMap extends HashMap<Long,Map<Integer,String>> { };
FooBarMap[] maps;
public FooBarMap getMapForType(int type)
{
// Actual code might be more complicated than this
return maps[type];
}
public String getDescription(int type, long fooId, int barId)
{
FooBarMap map = getMapForType(type);
return map.get(fooId).get(barId);
}
/* rest of code */
}
6 Réponses :
Le problème réel strong> est que cet idiome crée un couplage élevé entre votre pseudo typledef em> et votre code client. Cependant, depuis que vous utilisez nb fort> p>
Un IDE Java moderne devrait définitivement contribuer à traiter avec des types génériques compliqués. p> foobarmap code> en privé, il n'y a pas de véritables problèmes d'accouplement fort> (ce sont des détails de la mise en œuvre). p>
Si vous n'utilisez pas cet idiome, vous créez un couplage élevé entre la description de type long et complexe ( HASHMAP
@bacar Le problème est de savoir si quelqu'un peut utiliser un hashmap
foomap code>. Pour utiliser une API qui prend un
foomap code>, vous ne pouvez pas passer un hashmap. C'est-à-dire qu'ils ne sont que polymorphes dans une direction si déclare sur une méthode d'interface.
L'ancien argument lit comme il devrait être préféré d'utiliser octet [] code> au lieu de
chaîne code> dans de nombreuses API, mais
chaîne code> est choisi pour une raison, par exemple Pas besoin de penser à l'encodage du personnage et de trucs partout toujours. On ne serait jamais autorisé à des cartes spécialisées dans des interfaces, même si ces spécialisations comptent beaucoup aussi, pensez simplement à des ensembles triés par rapport à ceux sans ordre. Création de certains
foomap code> est parfaitement amende pour mieux décrire la structure et l'utilisation de types, assurez-vous que les gens utilisent réellement le même type si attendu, avoir un endroit pour documenter ce type, etc.
Pour les interfaces publiques, je n'aime pas voir des types génériques, car ils n'ont aucune signification. Pour moi voir une méthode avec un argument de hashmap
Le problème avec cette approche est que le code client perd l'utilité de la structure de données de carte.
Sans ce pseudo-typledef, je préférerais écrire
interface FooBarMap extends Map<Long,Map<Integer,String>> { }; class FooBarHashMap extends HashMap<Long,Map<Integer,String>> implements FooBarMap{ };
Pas vrai parce que le type dans l'exemple est privé, la route «Typedef» enregistre un peu de frappe car il vous suffit de remplacer la carte -> HASHMAP au même endroit du code.
Si je déclare un champ avec la carte de type, le compilateur ne me permettra pas d'appeler des méthodes qui ne sont pas déclarées dans l'interface. Et si je substitue la classe d'implémentation avec une autre carte d'implémentation de classe, tout le code continuera à fonctionner. Si je le déclare comme un hashmap, je peux appeler des méthodes hashmap. Et le type de substitution dans "Typedef" va casser le code. Si je veux un jour de charger ma carte de DB en utilisant Hibernate, je peux le faire. Si j'ai HASHMAP, je dois créer de nouvelles et copier le contenu de la carte donnée par Hibernate. En général, utiliser des interfaces partout où il est possible est fortement encourage. Cet idiome décourage-le.
Il a un bon point à ce sujet quand il s'agit de la mettre dans une interface publique. Cet idiome imite une forme de sucre syntaxique, elle ne devrait pas affecter ce que vous montrez à vos clients. P>
Mais je ne vois pas de bonne raison de ne pas l'utiliser localement, à condition que cela vous rend la vie plus facile et que vous êtes plus lisible - et vous avez connu ce que vous faites. Brian peut généraliser et conseiller fortement contre elle dans n'importe quelle situation, mais c'est sa sensation de Goetz: p p>
Si vous n'utilisez que dans une petite unité de code localisée, les problèmes sont petits, vrais. p>
chose est, de même que les gains: votre programme ne sera probablement même pas textuellement que vous ne référez pas à la pseudo-typledef 5+ fois, ce qui signifie que la zone est visible pour être non triviale. P >
Je ne voudrais probablement pas réécrire le code qui l'a fait, mais cela semble une mauvaise habitude d'entrer dans. P>
imo, le problème avec les anti-motifs Java est qu'ils encouragent la pensée en noir et blanc. P>
En réalité, la plupart des anti-motifs sont nuancés. Par exemple, l'article lié explique comment Pseudo-TypeDefs conduit à des API dont les signatures de type sont trop restrictives, trop liées à des décisions de mise en œuvre particulières, virales, etc. Mais tout cela est dans le contexte des API publiques. Si vous conservez des pseudo-typlefs à partir d'API publiques (c'est-à-dire les restreindre à une classe, ou peut-être un module), ils ne font probablement aucun préjudice réel et ils peuvent em> rendre votre code plus lisible. P>
Mon point est que vous devez comprendre em> les anti-motifs et faire votre propre jugement raisonné em> à propos de quand et où pour les éviter. Il suffit de prendre la position que "je vais jamais em> faire x parce qu'il est un anti-motif" signifie que parfois em> vous excluez pragmatiquement acceptable, voire de bonnes solutions. p>
Vous appelez ce type générique compliqué? Ha! Quand j'étais un garçon, nous devions nous lever à 3 heures du matin avec des génériques de six niveaux recouverts de ...
Aye ... sans chaussures ... montée ... dans la neige ..
@Marcus Downing: Et le septième niveau que vous mangez au petit-déjeuner au restaurant à la fin de la récursivité. ;-)
Nouvelle archive Lien vers l'article IBM ci-dessus: THÉORIE ET PRATIQUE JAVA: Pseudo-Typedef AntiPattern