2010-02-16 5 views
18

Duplizieren habe ich diesen Code:Wie fangen vermeiden komplizierte Blöcke

try { 
    do_stuff(); 
    return do_more_stuff(); 
} catch (UnsupportedEncodingException e) { 
    throw CustomException.programmer_error(e); 
} catch (ProtocolException e) { 
    throw CustomException.programmer_error(e); 
} catch (MalformedURLException e) { 
    throw CustomException.programmer_error(e); 
} catch (SocketTimeoutException e) { 
    throw new CustomException(e); 
} catch (IOException e) { 
    throw CustomException.unexpected_error(e); 
} 

ich jetzt all diese catch-Blöcke in einer anderen ähnlichen Funktion haben muß. Was ist der beste Weg, um Doppelarbeit zu vermeiden?

Beachten Sie, dass der Code in den beiden try-Blöcken nicht sehr ähnlich ist.

Auch ich kann nicht wirklich den Satz von Fängen höher setzen.

Hinweis, würde ich lieber vermeiden:

try { 
    do_stuff(); 
    return do_more_stuff(); 
} catch (Exception e) { 
    handle_exception_via_rtti(e); 
} 
+0

Warum möchten Sie die rtti Version vermeiden? – clamp

+0

Da dpb sagt "Wenn Ihr Code gerade Exception abfängt, und do_stuff und do_more_stuff später zusätzliche checked Ausnahmen hinzufügen, werden Sie wahrscheinlich nie von der Änderung und der Tatsache wissen, dass Ihr Code jetzt falsch sein könnte." – mxcl

+1

Persönlich würde ich Ihre Methode nur die ursprünglichen Ausnahmen werfen lassen. Sie tun nicht viel mit Ihren catch-Blöcken, um etwas zu "behandeln", außer das Umbrechen in einer CustomException. Welchen Wert hat dieses Hinzufügen? – duffymo

Antwort

7

Persönlich würde ich versuchen, die

do_stuff(); 
return do_more_stuff(); 

Teil einer allgemeineren Format, um Strategie anzuwenden konform zu machen (als Muster).

Dann können Sie alle Orte umgestalten, an denen Sie diese Art von Block aufrufen, so dass sie einen verallgemeinerten Block aufrufen können (wo die Fänge nur einmal angelegt werden).

+2

In der Tat wird das Strategie-Muster hier funktionieren. Für zukünftige Generationen würde dies bedeuten, dass "do_stuff(); Rückgabe von do_more_stuff() 'mit' return strategy.do_stuff() '. Daher übergeben Sie die Strategie an Ihre Ausnahmebehandlungsfunktion. Dieses Muster würde erfordern, dass alle Strategien denselben Typ von do_stuff() zurückgeben; – mxcl

5

Hinweis, würde ich lieber vermeiden:

Dann entweder nur mit ihr leben, oder warten, bis JDK7 kommt mit Multicatch, so dass Sie wie:

try { 
    do_stuff(); 
    return do_more_stuff(); 
} catch (UnsupportedEncodingException | ProtocolException | MalformedURLException e) { 
    throw CustomException.programmer_error(e); 
} catch (SocketTimeoutException e) { 
    throw new CustomException(e); 
} catch (IOException e) { 
    throw CustomException.unexpected_error(e); 
} 

Sie können dies auch in den Konstruktor CustomException verschieben und einen (fiesen) globalen Catch ausführen, aber dann müssen Sie eine Reihe von (bösartigen) if/else Blöcken hinzufügen, um den Typ der Ausnahmeursache zu bestimmen. Alles in allem würde ich es vorziehen, bei dem Weg zu bleiben, den Sie bereits getan haben.

Update: Eine andere Alternative ist, die Zeilen zu spalten/umzuformen, die möglicherweise die Ausnahme als separate Aufgaben in eine andere Methode wirft werfen CustomException wirft. Z.B.

try { 
    do_stuff_with_encoding(); 
    do_stuff_with_url(); 
    do_stuff_with_ws(); 
    // ... 
    return do_more_stuff(); 
} catch (SocketTimeoutException e) { 
    throw new CustomException(e); 
} catch (IOException e) { 
    throw CustomException.unexpected_error(e); 
} 

... 

public SomeObject do_stuff_with_encoding() throws CustomException { 
    try { 
     do_stuff(); 
    } catch (UnsupportedEncodingException e) { 
     throw CustomException.programmer_error(e); 
    } 
} 

public SomeObject do_stuff_with_url() throws CustomException { 
    try { 
     do_stuff(); 
    } catch (MalformedURLException e) { 
     throw CustomException.programmer_error(e); 
    } 
} 

public SomeObject do_stuff_with_ws() throws CustomException { 
    try { 
     do_stuff(); 
    } catch (ProtocolException e) { 
     throw CustomException.programmer_error(e); 
    } 
} 
+1

@BalusC: Leider wurde dieser Vorschlag abgelehnt: http://blogs.sun.com/darcy/entry/project_coin_final_five (Es sei denn jemand kann mich hier korrigieren ..) – Tim

+1

@Tim: Es wird jetzt für die Einbeziehung http: //blogs.sun.com/darcy/entry/projec_coin_post_devoxx_closures –

+0

@Ben: Danke! Das wusste ich nicht. Hoffen wir, dass sie es schließlich einschließen werden. – Tim

2

Es hängt davon ab, warum die do_stuff und do_more_stuff die geprüften Ausnahmen werfen. Machen sie das, um den Benutzer zu zwingen, die Ausnahme zu behandeln? Wenn ja, dann versuchen Sie zu vermeiden:

try { 
    do_stuff(); 
    return do_more_stuff(); 
} catch (Exception e) { 
    handle_exception_via_rtti(e); 
} 

ist eine gute Sache.

Wenn Ihr Code nur Exception fängt, und die do_stuff und do_more_stuff später zusätzliche Ausnahmen hinzufügen, werden Sie wahrscheinlich nie wissen, über die Änderung und die Tatsache, dass Ihr Code jetzt falsch sein könnte.

Sie müssen sich also möglicherweise mit throwing the kitchen sink befassen und alle diese Ausnahmen behandeln, es sei denn, die Methoden könnten auf ungeprüfte Ausnahmen wechseln.

Auf der anderen Seite, wenn die Methoden checked Ausnahmen werfen, nur weil der Programmierer war faul in der Behandlung mit ihnen und wollte nur den Bock übergeben, vielleicht sehen Sie dies aus dem falschen Blickwinkel.

+0

Dank Ihrem Kommentar hat mir geholfen, zu beurteilen, wie ich mich dem Problem näherte. In der Tat vermeide ich es, die Küchenspüle zu werfen, und ich gebe den Bock nicht weiter. – mxcl

1

Wie über eine generische Action-Klasse einzuführen, die subclassed werden können:

public class Action { 
    public void runWithHandlers() throws Exception { 
     try { 
      run(); 
     } catch (UnsupportedEncodingException e) { 
      throw CustomException.programmer_error(e); 
     } catch (ProtocolException e) { 
      throw CustomException.programmer_error(e); 
     } catch (MalformedURLException e) { 
      throw CustomException.programmer_error(e); 
     } catch (SocketTimeoutException e) { 
      throw new CustomException(e); 
     } catch (IOException e) { 
      throw CustomException.unexpected_error(e); 
     } 
    } 
    public void run() throws Exception { 
     // TODO subclasses of Action must implement this 
    } 
} 

Dann woanders in Ihrem Code instanziiert eine der Unterklassen von Aktion und rufen runWithHandlers():

new MyAction().runWithHandlers(); 
+0

Gute Antwort. Aber ich werde es dem Typen geben, der das Strategie-Muster vorgeschlagen hat, denke ich. Das ist ähnlich, und ehrlich gesagt bevorzuge ich es (es ist einfacher), aber ich denke, es ist sinnvoll, andere Menschen auf etwas leichter benannt zu nennen. – mxcl

+0

Meine Lösung hat eigentlich einen Namen: Es ist das bekannte Template-Methodenmuster, direkt aus dem GoF-Buch :-) –