2009-09-15 7 views
2

J'ai plusieurs (plus de 20) méthodes (getXXX()) qui peuvent lever une exception (un NotCalculatedException) lorsqu'elles sont appelées.Refactorisation d'une méthode qui appelle d'autres méthodes qui lancent Exception

Dans une autre méthode, j'ai besoin d'accéder aux résultats donnés par ces méthodes. Pour le moment, j'ai un code horrible, qui ressemble à:

public void myMethod() { 
    StringBuffer sb = new StringBuffer(); 
    // Get 'foo' result... 
    sb.append("foo = "); 
    try { 
     sb.append(getFoo()); 
    } catch (NotCalculatedException nce) { 
     sb.append("not calculated."); 
    } 
    // Get 'bar' result... 
    sb.append("\nbar = "); 
    try { 
     sb.append(getBar()); 
    } catch (NotCalculatedException nce) { 
     sb.append("not calculated."); 
    } 
    ... 
} 

Sans modifier les getXXX méthodes (donc ils doivent garder leur throws NotCalculatedException), comment voulez-vous factoriser/Simplifions myMethod() pour le rendre semble mieux?

S'il vous plaît noter que ce projet est encore en utilisant Java 1.4 :(


EDIT

Je ne peut mettre toutes les getXXX() méthodes dans le bloc try { ... }, comme StringBuffer sera être incomplet si une méthode lance NotCalculatedException

public void myMethod() { 
    StringBuffer sb = new StringBuffer(); 
    try { 
     sb.append("foo = "); 
     sb.append(getFoo()); 
     sb.append("\nbar = "); 
     sb.append(getBar()); 
    } catch (NotCalculatedException nce) { 
     sb.append("not calculated."); 
    } 
    ... 
} 

En d'autres termes, si getFoo() jette une NotCalculatedException, je veux avoir ce genre de sortie:

foo = not calculated 
bar = xxx 
... 

Si je mets tout en un seul try { ... }, j'aurai cette sortie, que je ne suis pas vouloir obtenir:

foo = not calculated 

Répondre

2

Je ne pense pas que vous devriez utiliser NotCalculatedException pour contrôler la logique.

Mais j'ai quelques idées à ce sujet.

  1. Vous avez besoin une autre méthode getter

    sb.append (this.getFoo ("non calculé"));

  2. Créer méthode hasValue

    sb.append (hasFoo() this.getFoo(): "pas calculé");

  3. Créer un getter générique

    sb.append (this.getValueByName ("foo"));

0

Vous pouvez stocker "foo", "bar" etc dans un tableau. En boucle autour de ceux-ci, imprimez chacun, puis utilisez la réflexion pour trouver/appeler le getFoo(), getBar() correspondant. Pas gentil, je l'admets. Voir l'objet Method pour plus d'informations.

EDIT: Vous pouvez également utiliser AspectJ pour entourer chaque appel de méthode getXXX() pour cet objet et intercepter l'exception.

+0

Oui, je pensais à l'aide de la réflexion, mais je n'aime vraiment pas cette solution (dans ce cas) ... – romaintaz

1

Pour chaque getXXX, vous pouvez ajouter un getXXXOrDefault() qui recouvre l'exception et renvoie la valeur getXXX ou "non calculé".

public void myMethod() {  
     StringBuffer sb = new StringBuffer();  
     // Get 'foo' result...  
     sb.append("foo = "); 
     sb.append(getFooOrDefault()); 
     // Get 'bar' result...  
     sb.append("\nbar = "); 
     sb.append(getBarOrDefault()); 
     // ... 
} 

public Object getFooOrDefault() { 
     try { 
       return getFoo(); 
     } catch() { 
       return "not calculated."; 
     } 
} 

Ou ... Utilisez Réflexion

public Object getValueOrDefault(String methodName) { 
     try { 
       // 1 . Find methodName 
       // 2 . Invoke methodName 
     } catch() { 
       return "not calculated."; 
     } 
} 

Mais je crois que je préfère encore la première option.

+0

Oui, c'est une idée, mais cela signifie que je voudrais créer 20 nouvelles méthodes. .. – romaintaz

+0

IMO, c'est une mauvaise idée. N'utilisez pas un objet, utilisez un wrapper qui stocke le retour de getFoo(), et un code (enum/int/bool quoi que ce soit) qui indique si la récupération s'est bien passée. –

+0

Je n'ai utilisé que Object car je ne connais pas le type de retour de getFoo ou getBar. Même ainsi, pourquoi le downvote? –

0

Vous pouvez utiliser l'idiome Execute Around. Malheureusement, la syntaxe Java est verbeuse, donc ce n'est pas une victoire dans les cas simples. En supposant NotCalculatedException est une exception unchekd.

appendThing(sb, "foo = ", new GetValue() { public Object get() { 
    return getFoo(); 
}}); 
appendThing(sb, "bar = ", new GetValue() { public Object get() { 
    return getBar(); 
}}); 

Un autre procédé laid combinerait une boucle et le commutateur:

int property = 0; 
lp: for (;;) { 
    String name = null; // Ugh. 
    try { 
     final Object value; 
     switch (property) { 
      case 0: name= "foo"; value = getFoo(); break; 
      case 1: name= "bar"; value = getBar(); break; 
      default: break lp; 
     } 
     ++property; 
     sb.append(name).append(" = ").append(value).append('\n'); 
    } catch (NotCalculatedException exc) { 
     sb.append(name).append(" = ").append("not calculated.\n"); 
    } 
} 

En variante, ont un enum et un commutateur pour chaque paramètre. N'utilisez pas de réflexion!

+0

Pourquoi le commentaire sur la réflexion? Est-ce un problème stylistique, ou y a-t-il une raison pour que cela ne fonctionne pas? (Je sais que j'ai suggéré une réflexion, et j'ai admis que ce n'était pas bien, mais je crois que ça * marchera *) –

+1

La réflexion est une bonne indication que quelque chose de très, très mal se passe. –

+0

La première option semble vraiment mauvaise à moins que Lambdas arrive à Java. Si vous avez une norme de formatage de code dans votre équipe (et qu'ils peuvent utiliser la valeur par défaut d'IDE). La réflexion en elle-même n'est pas mauvaise, le problème est que le langage Java n'a pas une méthode typée forte, avec une bonne syntaxe (déléguer en C#). –

1

Ma suggestion est plus de code, mais une meilleure lisibilité pour le myMethod:

public void myMethod() { 
    StringBuilder resultBilder = new StringBuilder(); 

    resultBuilder.append("foo="); 
    appendFooResult(resultBuilder); 
    resultBuilder.append("\nbar="); 
    appendBarResult(resultBuilder); 

    ... 
} 

private void appendFooResult(StringBuilder builder) { 
    String fooResult = null; 
    try { 
     fooResult = getFoo(); 
    } catch (NotCalculatedException nce) { 
     fooResult = "not calculated."; 
    } 
    builder.append(fooResult); 
} 

private void appendBarResult(StringBuilder builder) { 
    String barResult = null; 
    try { 
     barResult = getBar(); 
    } catch (NotCalculatedException nce) { 
     barResult = "not calculated."; 
    } 
    builder.append(barResult); 
} 
0

On dirait que Java ne dispose pas des délégués de la boîte comme C# - mais Google m'a montré qu'il ya ways to roll your own. Donc, ce qui suit peut être quelque chose à essayer ..

public static PrintProperty(JavaDelegateWithAName del, StringBuilder collector) 
{ 
    try 
    { 
    collector.append(del.Name+ " = "); 
    collector.append(del.Target.Invoke()); 
    } 
    catch(NotCalculatedException nce) 
    { collector.append("NotCalculated"); } 
} 

... principale

foreach(JavaDelegateWithAName entry in collectionOfNamedJavaDelegates) 
    SomeUtilityClass.PrintProperty(entry, sb); 
1

Je pense que vous devriez laisser votre code tel quel. C'est verbeux, mais très facile à dire, et il se comporte correctement.

+0

Ou, utilisez la suggestion de bruno de déplacer le try/catch dans les méthodes de couverture, qui semble un peu plus agréable –

+0

+1 Aucun point sur-élaborer quelque chose pour l'esthétique. – banjollity

Questions connexes