2010-02-16 9 views
18

mam ten kod:Jak uniknąć powielania skomplikowanych bloków catch

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); 
} 

Teraz trzeba mieć wszystkie te bloki catch w innej podobnej funkcji. Jaki jest najlepszy sposób na uniknięcie powielania?

Należy zauważyć, że kod wewnątrz dwóch bloków try nie jest bardzo podobny.

Również nie mogę umieścić zestawu chwytów wyżej.

Uwaga, wolałbym uniknąć:

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

dlaczego chcesz uniknąć wersji rtti? – clamp

+0

Gdy dpb mówi "Jeśli twój kod po prostu łapie wyjątek, a doWWWP i do_więcej razy później dodają dodatkowe sprawdzone wyjątki, prawdopodobnie nigdy nie dowiesz się o zmianie i tym, że twój kod może być teraz nieprawidłowy." – mxcl

+1

Osobiście chciałbym, aby Twoja metoda wyrzuciła oryginalne wyjątki. Nie robi się zbyt wiele z blokami catch, aby "obsłużyć" wszystko poza pakowaniem w wyjątek CustomException. Jaką wartość ma to dodanie? – duffymo

Odpowiedz

7

Osobiście staram się uczynić

do_stuff(); 
return do_more_stuff(); 

część odpowiadają bardziej ogólnej formie w celu zastosowania strategii (jako wzór).

Następnie możesz odmienić wszystkie miejsca, w których nazywasz ten blok, aby mogli zadzwonić do bardziej uogólnionego bloku (gdzie złapane są tylko jeden raz).

+2

Rzeczywiście wzorzec strategii będzie tutaj działał. Dla przyszłych pokoleń będzie to wymagało zastąpienia 'do_stuff(); return do_more_stuff() 'z' return strategy.do_stuff() '. W ten sposób przekazujesz strategię do funkcji obsługi wyjątków. Ten wzorzec wymagałby wszystkich strategii, aby zwrócić ten sam typ z do_stuff(); – mxcl

5

Uwaga, wolałbym uniknąć:

następnie albo po prostu z tym żyć, albo czekać aż JDK7 pochodzi z Multicatch, dzięki czemu można napisać od nowa:

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); 
} 

Możesz również przenieść to do konstruktora CustomException i zrobić (nieprzyjemny) globalny połów, ale musisz dodać kilka (nieprzyjemnych) bloków if/else, aby określić typ przyczyny wyjątku. W sumie wolałbym trzymać się tej drogi, co już zrobiłeś.

Aktualizacja: Inną alternatywą jest podzielony/byłaby linie, które potencjalnie mogą rzucić wyjątek jako odrębne zadania w kolejnych blokach metoda rzucania CustomException. Na przykład.

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: Niestety, ta propozycja została odrzucona: http://blogs.sun.com/darcy/entry/project_coin_final_five (Chyba, że ​​ktoś tutaj może mnie poprawić w tym ..) – Tim

+1

@Tim: To jest teraz ponownie rozważane w celu uwzględnienia http: //blogs.sun.com/darcy/entry/projec_coin_post_devoxx_closures –

+0

@Ben: Dzięki! Nie wiedziałem o tym. Miejmy nadzieję, że uwzględnią to mimo wszystko. – Tim

2

Zależy to od tego, dlaczego do_stuff i rzucają sprawdzane wyjątki. Czy robią to, aby zmusić użytkownika do potraktowania wyjątku? Jeśli tak, to próbujesz uniknąć:

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

to dobrze.

Jeśli kod tylko łapie Exception i do_stuff i do_more_stuff później dodać dodatkowe wyjątki, nigdy zapewne wie o zmianie oraz fakt, że kod może teraz być w błędzie.

Możesz więc poradzić sobie z throwing the kitchen sink i traktować wszystkie te wyjątki, chyba że metody mogą przejść do niezaznaczonych wyjątków.

Z drugiej strony, jeśli metody rzucają sprawdzane wyjątki tylko dlatego, że programista był leniwy w traktowaniu z nimi i po prostu chciał przekazać pieniądze, może patrzysz na to pod niewłaściwym kątem.

+0

Dzięki waszemu komentarzowi naprawdę pomogła mi ocenić, w jaki sposób podchodziłem do problemu. Rzeczywiście unikam rzucania zlewu w kuchni, a ja nie przerzucam złotówki. – mxcl

1

Jak o wprowadzenie rodzajowe klasy działania, które mogą być podklasy:

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 
    } 
} 

Potem gdzieś w kodzie wystąpienia jednej z podklas działania i zadzwonić runWithHandlers():

new MyAction().runWithHandlers(); 
+0

Dobra odpowiedź. Ale dam to do faceta, który sugerował wzór strategii, myślę. Jest to podobne i szczerze mówiąc wolę (jest to prostsze), ale uważam, że rozsądnie jest wskazywać innym na coś, co jest łatwiejsze do nazwania. – mxcl

+0

Moje rozwiązanie faktycznie ma nazwę: Jest to dobrze znany wzór metody szablonu, bezpośrednio z książki GoF :-) –

Powiązane problemy