2010-03-07 4 views
2

J'ai du mal à trouver moyen de factoriser correctement ce code afin qu'il y aurait aussi peu de code en double que possible, j'ai deux ou trois méthodes comme celui-ci (pseudocode):Comment refactoriser correctement ceci?

public List<Something> parseSomething(Node n){ 
    List<Something> somethings = new ArrayList<Something>(); 
    initialize(); 
    sameCodeInBothClasses(); 
    List<Node> nodes = getChildrenByName(n, "somename"); 
    for(Node n:nodes){ 
    method(); 
    actionA(); 
    somethings.add(new Something(actionB()); 
    } 
    return somethings; 
} 

méthodes sameCodeInBothClasses() sont les mêmes dans toutes les classes mais où il diffère est ce qui se passe dans la boucle actionA() et il ajoute également un élément à la liste de type différent.

Dois-je utiliser le modèle de stratégie pour les différentes parties à l'intérieur de la boucle?

Qu'en est-il de la valeur de retour (Le type de liste diffère), si la méthode retourne juste List<Object> que je convertirais alors en type approprié? Dois-je passer la classe que je veux revenir en paramètre?

+0

les méthodes 'sameCodeInBothClasses()', 'method()', 'actionA()' provoquent-elles des effets secondaires? En d'autres termes, cette méthode d'analyse fait-elle plus que simplement analyser quelque chose du nœud donné? – Anurag

Répondre

1

Le motif de conception applicable est Template Method, plutôt que Stratégie.

sur les différents types d'articles, je voudrais essayer genericizing parseSomething d'abord, comme ceci:

public <T> List<T> parseSomething(Node n){ 
    List<T> somethings = new ArrayList<T>(); 
    initialize(); 
    sameCodeInBothClasses(); 
    List<Node> nodes = getChildrenByName(n, "somename"); 
    for(Node n:nodes){ 
    method(); 
    actionA(); 
    somethings.add(new T(actionB()); 
    } 
    return somethings; 
} 

Cela peut ne pas fonctionner pour vous tout de suite bien. Vous devrez peut-être déplacer le paramètre générique au niveau de la classe.

De retour List<Object> ne fonctionnera pas, car les collections génériques sont invariant: pour les deux types distincts Type1 et Type2, List<Type1> est ni un sous-type, ni un supertype List<Type2> (même si Type1 et Type2 sont liés, à savoir un est un sous-type de l'autre!). Voir an earlier answer of mine pour plus de détails à ce sujet.

Donc, si tout le reste échoue, la solution rapide et sale serait en effet d'utiliser un List non générique.

+0

Merci, cela fonctionne bien, plus j'ai aussi utilisé le modèle de stratégie de sorte que la seule chose qui se passe dans la boucle for est genericParser.doTheStuff(), où un analyseur concret (implémentation de l'interface GenericParser) est passé à l'exécution. assez content de cette solution car il n'y a plus de code dupliqué. – kane77

1

Si vous écrivez comme ceci:

public List<T> parseGeneric(Node n) { 
    List<T> result = new ArrayList<T>(); 
    initialize(); 
    sameCodeInBothClasses(); 
    List<Node> nodes = getChildrenByName(n, "somename"); 
    for(Node n:nodes){ 
    method(); 
    actionA(); 
    result.add(new T(actionB())); 
    } 
    return result; 
} 

Et invoquez comme

List<Something> somethings = parseGeneric(aSomething); 

Il est difficile de dire avec toutes ces autres méthodes saupoudrés autour sans définition disponible, mais je crois que vous devriez être en mesure de s'en tirer avec quelque chose comme ce qui précède.

0

Je créer une interface d'action pour les méthodes actionA et actionB. Ensuite, une classe Parser avec une méthode parseSomething:

public List parseSomething(Node n, Action a) { 
    List something = new ArrayList(); 
    initialize(); 
    samecode(); 
    List<Node> nodes = getChildrenByName(n, "name"); 
    for(Node n: nodes) { 
     a.actionA(); 
     somethings.add(new Something(a.actionB())); 
    } 
    return somethings; 
} 
1

Ma première idée serait de déclarer parseSomething dans une classe de base abstraite, les méthodes qui sont différentes pour chaque classe déclarée comme abstract et mis en œuvre dans les sous-classes. Le code en ligne qui crée une instance Something devra être transformé en méthode d'usine.

Le problème est que la signature de parseSomething doit renvoyer des types théoriquement différents; par exemple. List<Something> contre List<SomethingElse>. Une approche serait d'identifier un supertype commun et de faire le type de retour List<? extends SomeSuper>.Une autre approche consiste à créer des méthodes parseXxx avec les signatures requises dans chaque classe feuille et à les déléguer à une méthode protected List<? extends SomeSuper> doParse(...) dans la classe de base.