2010-04-23 3 views
4

Il y a des tâches qui ne doivent pas être effectuées en parallèle (par exemple ouvrir un fichier, lire, écrire et fermer, il y a un ordre sur cela. ..)Gestion des exceptions Java dans les tâches non séquentielles (modèle/bonne pratique)

mais ... Certaines tâches sont plus comme une liste shoping, je veux dire qu'ils pourraient avoir un ordre souhaitable, mais ce n'est pas un must..example dans les pilotes de independient de communication ou de chargement etc ..

Pour ce genre de tâches, Je voudrais savoir une meilleure pratique java ou un modèle pour gérer les exceptions ..

La manière simple de java est:

getUFO { 
     try { 
      loadSoundDriver(); 
      loadUsbDriver(); 
      loadAlienDetectorDriver(); 
      loadKeyboardDriver();  
    } catch (loadSoundDriverFailed) { 
    doSomethingA; 
    } catch (loadUsbDriverFailed) { 
     doSomethingB; 
    } catch (loadAlienDetectorDriverFailed) { 
     doSomethingC; 
    } catch (loadKeyboardDriverFailed) { 
     doSomethingD; 
    } 
} 

Mais qu'en ayant une exception dans l'une des actions, mais vouloir essayer avec les prochains ??

J'ai pensé cette approche, mais ne semble être une bonne utilisation des exceptions Je ne sais pas pas si cela fonctionne, n'a pas d'importance, il est vraiment terrible !!

getUFO { 
     Exception ex=null; 
try { 
     try{ loadSoundDriver(); 
     }catch (Exception e) { ex=e; } 
     try{ loadUsbDriver(); 
     }catch (Exception e) { ex=e; } 
     try{ loadAlienDetectorDriver(); 
     }catch (Exception e) { ex=e; } 
     try{ loadKeyboardDriver() 
     }catch (Exception e) { ex=e; } 

     if(ex!=null) 
     { throw ex; 
     } 
    } catch (loadSoundDriverFailed) { 
    doSomethingA; 
    } catch (loadUsbDriverFailed) { 
     doSomethingB; 
    } catch (loadAlienDetectorDriverFailed) { 
     doSomethingC; 
    } catch (loadKeyboardDriverFailed) { 
     doSomethingD; 
    } 
} 

ne semble pas compliqué de trouver une meilleure pratique pour le faire .. Je ne l'ai pas encore

Merci pour tout conseil

+0

La partie centrale de la question est de savoir comment faire un code aussi propre que le premier, mais fonctionnel comme le second (il n'interrompt pas le processus et laisse essayer les instructions suivantes). Et bien sûr ce serait génial si non seulement laisser essayer les suivants, mais si cela permettait de "réessayer" les échecs ... –

Répondre

1

OMI, pour votre cas, si l'exception est « ignorable » il est préférable que la méthode "loadSoundDriver" capture l'exception et renvoie simplement une erreur. Puis, dans la fonction qui charge les choses, vous pouvez enregistrer toutes les erreurs et, à la fin de la séquence, décider quoi en faire. [modifier] Quelque chose comme ceci:

// init 
MyError soundErr = loadSoundDriver(); 
MyError otherErr = loadOtherDriver(); 

if(soundErr!=null || otherErr !=null){ 
// handle the error(s) 
} 
5

Considérons le execute around idiom.

Une autre option (qui n'est pas vraiment différente, il suffit de les découpler davantage) consiste à faire chaque tâche dans un fil séparé.

Edit:

Voici le genre de chose que j'ai à l'esprit:

public interface LoadableDriver { 
    public String getName(); 
    public void loadDriver() throws DriverException; 
    public void onError(Throwable e); 
} 

public class DriverLoader { 
    private Map<String, Exception> errors = new HashMap<String, Exception>(); 

    public void load(LoadableDriver driver) { 
     try { 
      driver.loadDriver(); 
     } catch (DriverException e) { 
      errors.put(driver.getName(), e); 
      driver.onError(e); 
     } 
    } 

    public Map<String, Exception> getErrors() { return errors; } 
} 

public class Main { 
    public void loadDrivers() { 
      DriverLoader loader = new DriverLoader(); 
      loader.loadDriver(new LoadableDriver(){ 
       public String getName() { return "SoundDriver"; } 
       public void loadDriver() { loadSoundDriver(); } 
       public void onError(Throwable e) { doSomethingA(); } 
      }); 
      //etc. Or in the alternative make a real class that implements the interface for each driver. 
      Map<String, Exception> errors = loader.getErrors(); 
      //react to any specific drivers that were not loaded and try again. 
     } 
} 

Edit: Voici ce qu'est une version Java propre regarderait en fin de compte comme si vous mis à exécution les pilotes comme des classes (qui est ce que le paradigme Java OO attendrait ici IMHO). La méthode Main.loadDrivers() changeraient comme ceci:

 public void loadDrivers(LoadableDriver... drivers) { 
      DriverLoader loader = ... 
      for(LoadableDriver driver : drivers) { 
       loader.load(driver); 
      } 
      //retry code if you want. 
      Set<LoadableDriver> failures = loader.getErrors(); 
      if(failures.size() > 0 && tries++ > MAX_TRIES) { 
       //log retrying and then: 
       loadDrivers(drivers.toArray(new LoadableDriver[0])); 
      } 
     } 

Bien sûr, je n'utilise plus une carte parce que les objets seraient autonomes (vous pouvez vous débarrasser de la méthode getName() aussi, mais probablement devrait surcharger toString()), donc les erreurs sont juste renvoyées dans un ensemble à réessayer. Vous pourriez rendre le code de réessai encore plus simple si chaque pilote était responsable de savoir à quelle fréquence il devrait réessayer. Java ne sera pas aussi beau qu'un gabarit C++ bien fait, mais c'est le choix du langage Java - préférez la simplicité aux fonctionnalités de langage complexes qui peuvent rendre le code difficile à maintenir dans le temps s'il n'est pas fait correctement.

+0

@Dave, bien qu'il n'y ait pas de nettoyage, il y a une gestion des exceptions qui est gentille de la même chose (comme vous avez besoin d'exécuter autour pour le gérer). Je vais essayer d'éliminer ce que j'ai en tête. – Yishai

+0

Cette approche semble être vraiment plus complexe, je suis tenté de penser qu'il n'y a aucun moyen de le faire nettoyer avec Java (en C++ je pourrais écrire quelques macros pour au moins garder le code visible très propre) –

+0

Eh bien c'est définitivement verbeux (voir mon lien où Jon Skeet explique pourquoi il est si pénible en Java), mais il gère les scénarios supplémentaires que vous demandez - réessayer et la gestion des erreurs personnalisées. Si le but était de rendre cette routine agréable, commencez par demander à chaque pilote d'implémenter cette interface. Ensuite, il commencerait à devenir très propre. Avoir le conducteur en mesure d'être une clé dans la carte, même plus propre, puis transformer le chargement en une méthode récursive, encore mieux. Ce que ce code vous apporte sur votre version, c'est qu'il est beaucoup moins sujet aux erreurs lors de l'ajout de pilotes que l'autre version. Je vais écrire une "version propre". – Yishai

3

Essayez ceci:

protected void loadDrivers() { 
    loadSoundDriver(); 
    loadUsbDriver(); 
    loadAlienDetectorDriver(); 
    loadKeyboardDriver();  
} 

Puis:

protected void loadSoundDriver() { 
    try { 
    // original code ... 
    } 
    catch(Exception e) { 
    soundDriverFailed(e); 
    } 
} 

protected void soundDriverFailed(Exception e) { 
    log(e); 
} 

Cela donne une chance de sous-classes changer le comportement. Par exemple, une sous-classe pourrait implémenter le chargement de chaque pilote dans un thread séparé. La classe principale n'a pas besoin de savoir comment les pilotes sont chargés, ni les utilisateurs de la classe principale.

+0

+1 Votre solution est réellement abondante la même que la mienne, juste mieux :) – Virgil

0

Entourez simplement chaque opération de chargement avec son propre bloc try/catch.

try { 
    loadSoundDriver(); 
} catch (loadSoundDriverFailed) { 
    doSomethingA; 
} 

try { 
    loadUsbDriver(); 
} catch (loadUsbDriverFailed) { 
    doSomethingB; 
} 

    // ... 

Vous pouvez donc gérer toutes les exceptions et continuer le traitement des opérations.

+0

J'ai déjà mis de cette façon, comme la laide, je cherchais une alternative propre –