Meilleure façon de retourner le drapeau d'état et le message d'une méthode en Java

j'ai un scénario trompeusement simple, et je veux une solution simple, mais ce n'est pas évident ce qui est" le plus correct "ou"le plus Java".

disons que j'ai une petite méthode d'authentification(client client) dans une certaine classe. L'authentification pourrait échouer pour un certain nombre de raisons, et je veux retourner un booléen simple pour le flux de contrôle, mais aussi retourner un message de chaîne de caractères pour l'utilisateur. Ce sont les possibilités auxquelles je peux penser:

  • retour a booléen, et passer dans un StringBuilder pour recueillir le message. C'est la plus proche d'un style C moyen de le faire.
  • lancer une exception au lieu de retourner false, et inclure le message. Je n'aime pas cela, car l'échec n'est pas exceptionnel.
  • crée une nouvelle classe appelée AuthenticationStatus avec le booléen et la corde. Cela semble exagéré pour une petite méthode.
  • Stockez le message dans une variable membre. Ce serait introduire une condition de race potentielle, et je n'aime pas que cela implique un État qui n'est pas vraiment là.

D'autres suggestions?

Modifier Raté cette option off

  • Retourner la valeur null pour le succès - Est-ce dangereux?

Modifier Solution:

je suis allé pour la solution la plus OO et a créé un petit AuthenticationResult classe. Je ne le ferais pas dans une autre langue, mais J'aime bien Java. J'ai aussi aimé la suggestion de retourner une chaîne [] puisque c'est comme le retour nul mais plus sûr. Un avantage de la classe de résultat est que vous pouvez avoir un message de succès avec plus de détails si nécessaire.

26
demandé sur Draemon 2008-12-10 17:32:31

17 réponses

retourner un petit objet avec à la fois le drapeau booléen et la corde à l'intérieur est probablement la façon la plus OO-like de le faire, bien que je convienne que cela semble exagéré pour un cas simple comme celui-ci.

une autre alternative est de toujours retourner une chaîne, et avoir null (ou une chaîne vide - vous choisissez lequel) indique le succès. Tant que les valeurs de retour sont clairement expliquées dans les javadocs, il ne devrait pas y avoir de confusion.

10
répondu Ashley Mercer 2008-12-10 14:36:26

vous pouvez utiliser des exceptions....

try {
    AuthenticateMethod();
} catch (AuthenticateError ae) {         
    // Display ae.getMessage() to user..
    System.out.println(ae.getMessage());
    //ae.printStackTrace();    
}

et ensuite si une erreur se produit dans votre méthode D'authentification, vous envoyez une nouvelle Authentifiererror (étend Exception)

13
répondu adam 2008-12-10 14:40:15

éviter de retourner une" valeur sentinelle", surtout nulle. Vous finirez avec une base de codes où les méthodes ne peuvent pas être comprises par l'appelant sans lire l'implémentation. Dans le cas de null, les appelants peuvent se retrouver avec NullPointerExceptions s'ils oublient (ou ne savent pas) que votre méthode peut retourner null.

la suggestion de tuple de Bas Leijdekkers est une bonne suggestion que j'utilise tout le temps si je veux retourner plus d'une valeur d'une méthode. Celui que nous utilisons est P2<A, B> de la Fonctionnel Java de la bibliothèque. Ce type de type est une union commune de deux autres types (il contient une valeur de chaque type).

exceptions de lancer pour le flux de contrôle est un peu d'une odeur de code, mais les exceptions vérifiées sont une façon d'obtenir plus d'un type de valeur d'une méthode. Il existe cependant d'autres possibilités plus propres.

  1. vous pouvez avoir un Option<T> classe abstraite avec deux sous-classes Some<T> et None<T> . C'est un peu comme une alternative de type-safe à null, et une bonne façon d'implémenter des fonctions partielles (fonctions dont la valeur de retour n'est pas définie pour certains arguments). La bibliothèque "Java fonctionnel a une classe complète Option qui implémente Iterable<T> , donc vous pouvez faire quelque chose comme ceci:

    public Option<String> authenticate(String arg) {
       if (success(arg))
          return Option.some("Just an example");
       else
          return Option.none();
    }
    
    ...
    
    for(String s : authenticate(secret)) {
       privilegedMethod();
    }
    
  2. alternativement, vous pouvez utiliser une union disjointe de deux types, comme une Either<L, R> classe. Il contient une valeur qui est soit de type L ou R . Cette classe implémente Iterable<T> pour les deux L et R , donc vous pouvez faire quelque chose comme ceci:

    public Either<Fail, String> authenticate(String arg) {
       if (success(arg))
          return Either.right("Just an example");
       else
          return Either.left(Fail.authenticationFailure());
    }
    
    ...
    
    Either<Fail, String> auth = authenticate(secret);
    for(String s : auth.rightProjection()) {
       privilegedMethod();
    }
    for(Fail f : auth.leftProjection()) {
       System.out.println("FAIL");
    }
    

Toutes ces classes, P2 , Option , et Either sont utiles dans une grande variété de situation.

8
répondu Apocalisp 2008-12-10 19:25:50

quelques autres options:

  • retourner une valeur enum distincte pour chaque type de défaillance. L'objet enum pourrait contenir le message
  • retourner un int et avoir une méthode séparée qui regarde le message approprié d'un tableau
  • crée une classe tuple d'utilité générique qui peut contenir deux valeurs. Une telle classe peut être utile dans beaucoup d'autres endroits.

exemple de tuple simple,

class Tuple<L, R> {

    public final L left;
    public final R right;

    public Tuple( L left, R right) {
        this.left = left;
        this.right = right;
    }
}
3
répondu Bas Leijdekkers 2008-12-10 14:42:24

vous pourriez retourner un ensemble de messages d'erreur, vides indiquant qu'il n'y avait pas de problèmes. C'est une amélioration de votre troisième proposition.

1
répondu sblundy 2008-12-10 14:35:18

je pense personnellement que la création d'une nouvelle classe appelée AuthenticationStatus avec le booléen et la chaîne est la façon la plus Java comme. Et bien que cela semble exagéré (ce qui pourrait bien être le cas), cela me semble plus propre et plus facile à comprendre.

1
répondu Jacob Schoen 2008-12-10 14:37:00

ce n'est pas parce qu'une authentification défaillante est banale que cela ne veut pas dire qu'elle n'est pas exceptionnelle.

à mon avis, les échecs d'authentification sont le poster-enfant cas d'utilisation pour les exceptions vérifiées. (Bien... peut-être que la non-existence du fichier est le cas d'utilisation canonique, mais l'échec de l'authentification est une fermeture #2.)

1
répondu benjismith 2008-12-10 15:34:29

j'utilise la "classe minuscule" moi-même, généralement avec une classe intérieure. Je n'aime pas utiliser des arguments pour recueillir des messages.

aussi, si la méthode qui pourrait échouer est" de bas niveau " - comme venant d'un serveur d'application ou de la couche de base de données, je préférerais retourner un Enum avec le statut de retour, et puis traduire cela dans une chaîne au niveau de L'interface graphique. Ne passez pas les chaînes d'utilisateurs au bas de l'échelle si vous allez un jour internationaliser votre code, car alors votre serveur d'applications peut seulement répondre dans une langue à la fois, plutôt que d'avoir des clients différents travaillant dans des langues différentes.

0
répondu Paul Tomblin 2008-12-10 14:37:50

Est-ce la seule méthode où vous avez une telle exigence? Si ce n'est pas le cas, il suffit de générer une classe de réponse générale avec un drapeau issuccessiful et une chaîne de messages, et de l'utiliser partout.

ou vous pourriez juste avoir la méthode de retour null pour montrer le succès (pas jolie, et ne permet pas de retourner un succès et un message).

0
répondu Michael Borgwardt 2008-12-10 14:39:24

je choisirais probablement quelque chose comme :


class SomeClass {
public int authenticate (Client client) {
//returns 0 if success otherwise one value per possible failure
}
public String getAuthenticationResultMessage (int authenticateResult) {}
//returns message associated to authenticateResult
}

Avec ce "design", vous pouvez demander un message uniquement lorsque l'authentification échoue (ce qui, je l'espère, est le scénario qui se produit 99,99% du temps ;))

il peut également être de bonne pratique de déléguer la résolution des messages à une autre classe. Mais cela dépend de vos besoins d'application (la plupart du temps, a-t-il besoin de i18n ?)

0
répondu Olivier 2008-12-10 14:58:35

cela semble être un idiome courant dans d'autres langages de programmation, mais je ne peux pas comprendre lequel ( C je suppose que je lis dans la question ) .

presque la même question est affichée ici et ici

tenter de retourner deux valeurs à partir d'une seule fonction, peut être trompeur. Mais comme il a été prouvé par les tentatives de le faire, il peut être très utile aussi.

Certainement créer et petite classe avec les résultats devrait être la bonne façon de procéder si c'est un flux commun dans l'application comme posté avant.

Voici une citation sur le retour de deux valeurs d'une fonction:

Comme une question de style de programmation, cette idée n'est pas attrayants dans un langage de programmation orienté objet. Retourner des objets pour représenter des résultats de calcul est le l'idiome pour le retour de plusieurs valeur. Quelque suggérer que vous ne devriez pas avoir à déclarer des classes pour des valeurs indépendantes, mais ni l'un ni l'autre ne devrait être indépendant les valeurs sont retournées à partir d'une seule méthode.

j'ai trouvé dans une requête de fonctionnalité pour java d'autoriser multiple return values

regardez la section "évaluation" datée du: 2005-05-06 09:40:08

0
répondu OscarRyz 2017-05-23 12:02:11

L'authentification réussie doit être le cas" normal", donc un échec d'authentification est le cas exceptionnel.

Quelles sont les différentes chaînes d'état pour l'utilisateur de toute façon. Je peux voir seulement deux, le succès ou l'échec. Toute information supplémentaire est un problème de sécurité potentiel. Un autre avantage de la solution avec des exceptions est qu'elle ne peut pas être appelée de la mauvaise manière et que le cas d'échec est plus évident. Sans exception, vous écrivez:

if (authenticate()) {
  // normal behaviour...
}
else {
  // error case...
}

Vous pouvez accidentellement appeler la méthode en ignorant la valeur de retour. Le code" comportement normal "est alors exécuté sans authentification réussie:

authenticate();
// normal behaviour...

si vous utilisez des exceptions, cela ne peut pas se produire. Si vous décidez de ne pas utiliser les exceptions, au moins nommez la méthode pour qu'il soit clair qu'elle retourne un État, E. G.:

if (isAuthenticated()) {
//...
}
0
répondu Markus 2008-12-10 17:26:40

il y a beaucoup de bonnes réponses ici donc je vais faire court.

je pense que le défaut d'authentification d'un utilisateur peut être considéré comme un cas valide pour une exception cochée. Si votre style de programmation favorisait les exceptions, il n'y aurait aucune raison de ne pas le faire. Il supprime également le "Comment retourner des valeurs multiples d'une méthode, ma méthode fait une chose il authentifie un utilisateur"

Si vous allez retourner plusieurs valeurs Passez 10 minutes à créer un PairTuple générique (peut aussi être plus qu'un TripleTuple de paire, Je ne vais pas répéter l'exemple ci-dessus) et retourner vos valeurs de cette façon. Je déteste avoir de petits objets de style dto pour retourner diverses valeurs multiples ils encombrent juste l'endroit.

0
répondu Shawn Vader 2008-12-10 18:04:58

Que Diriez-vous de retourner une corde? Vide ou Null pour le succès. Message d'erreur en cas d'échec. La plus simple qui fonctionne. Cependant pas sûr si elle lit bien.

-1
répondu Gishu 2008-12-10 14:36:54

retournez l'objet. Il vous permet de mettre des fonctionnalités supplémentaires dans la Classe, si vous en avez besoin. Les objets éphémères en Java sont rapides à créer et à collecter.

-1
répondu Javamann 2008-12-10 16:21:56

je choisirais l'option D'Exception en premier lieu.

mais, en deuxième place, je préférerais la technique du style C:

public boolean authenticate(Client client, final StringBuilder sb) {
    if (sb == null)
        throw new IllegalArgumentException();
    if (isOK()) {
        sb.append("info message");
        return true;
    } else {
        sb.append("error message");
        return false;
    }
}

Ce n'est pas si étrange et c'est fait dans de nombreux endroits dans le cadre.

-1
répondu bruno conde 2008-12-10 14:48:46

au lieu de créer un objet spécial pour le type de retour, je renvoie habituellement juste un tableau où toutes les informations retournées sont stockées. L'avantage est que vous pouvez étendre ce tableau avec de nouveaux éléments sans créer de nouveaux types et le désordre. L'inconvénient, Vous devez savoir exactement ce que les éléments devraient présenter lorsque le tableau est retourné de la méthode particulière pour l'analyser correctement. Habituellement je suis d'accord sur une certaine structure, comme premier élément est toujours indication booléenne succès, deuxième est la chaîne avec description, le reste est facultatif. Exemple:

public static void main(String[] args)
{
    Object[] result = methodReturningStatus();
    if(!(Boolean)result[0])
        System.out.println("Method return: "+ result[1]);
}

static Object[] methodReturningStatus()
{
    Object[] result = new Object[2];

    result[0] = false;
    result[1] = "Error happened";

    return result;
}
-2
répondu Ma99uS 2008-12-10 14:50:13