• 15 heures
  • Facile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 28/01/2019

Retournez vos méthodes

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Je ne vous ai pas encore parlé du retour de valeur dans une méthode. Une méthode a la possibilité de retourner un résultat : une valeur de n'importe quel type (int , double , String , etc.)

Vous avez déjà pu voir cette fonctionnalité avec String.contains . Une valeur de type  boolean  est retournée par  contains .

Pour récupérer une version propre du projet prêt pour ce chapitre, vous pouvez importer le projet git suivant : MyMenu - Step 7

Le premier return !

Nous voulons que  askSomething  puisse fonctionner avec la question du menu. Actuellement ce n'est pas possible.  askSomething  ne peux pas lancer  askSide  et  askDrink  en fonction du choix du menu.

Nous allons faire en sorte que  askSomething  retourne le numéro de la réponse choisie par l'utilisateur. Avec ce numéro nous pourrons faire un  switch , pour appeler  askSide  et  askDrink .

La première chose à faire est de rajouter 2 tests :

@Test
public void Given_Response2_When_AskAboutCarWithThreeResponses_Then_ReturnNumber2() {
    System.setIn(new ByteArrayInputStream("5\n2\n".getBytes()));
    order = new Order();
    String[] responses = {"BMW", "Audi", "Mercedes"};
    int choice = order.askSomething("voiture", responses);
    assertEquals(2, choice);
}
@Test
public void Given_Chiken_When_AskAboutMenus_Then_Return1() {
    System.setIn(new ByteArrayInputStream("1\n".getBytes()));
    order = new Order();
    int choice = order.askMenu();
    assertEquals(1, choice);
}

On demande ensuite à IntelliJ de modifier la signature de chaque méthode :

Changer la signature
Changer la signature

IntelliJ est plutôt doué pour la génération de code. Premièrement, il a changé la signature de  askSomething  :

public int askSomething(String category, String[] responses) {

Deuxièmement, il a vu que la seule variable int présente dans askSomething était nbResponse. Il a donc ajouté la ligne suivante :

return nbResponse;

C'est aussi simple que ça pour retourner une valeur. Comme vous le voyez dans le test,  askSomething  retourne une valeur de type  int  que l'on peut placer dans la variableint choice .

 askSomething  contient désormais le code suivant  :

/**
 * Display a question about a category in the standard input, get response and display it
 * @param category the category of the question
 * @param responses available responses
 * @return the number of the selected choice
 */
 public int askSomething(String category, String[] responses) {
        System.out.println("Choix " + category);
        for (int i = 1; i <= responses.length; i++)
            System.out.println(i + " - " + responses[i - 1]);
        System.out.println("Que souhaitez-vous comme " + category + "?");
        int nbResponse;
        boolean responseIsGood;
        do {
            nbResponse = sc.nextInt();
            responseIsGood = (nbResponse >= 1 && nbResponse <= responses.length);
            if (responseIsGood)
                System.out.println("Vous avez choisi comme " + category + " : " + responses[nbResponse - 1]);
            else {
                boolean isVowel = "aeiouy".contains(Character.toString(category.charAt(0)));
                if (isVowel)
                    System.out.println("Vous n'avez pas choisi d'" + category + " parmi les choix proposés");
                else
                    System.out.println("Vous n'avez pas choisi de " + category + " parmi les choix proposés");
            }
        } while (!responseIsGood);
        return nbResponse;
    }

Utilisez la génération automatique d'IntelliJ sur  askMenu . 

/**
 * Display a question about menu in the standard input, get response and display it
 */
public int askMenu() {
    String[] menus = {"poulet", "boeuf", "végétarien"};
    askSomething("menu", menus);
    return 0;
}

Cette fois, IntelliJ se débrouille moins bien. Il n'a pas trouvé de variable de type  int  dans le code. Il  retourne donc  0  par défaut. On va le modifier :

/**
 * Display a question about menu in the standard input, get response and display it
 * @return the number of the selected menu
 */
public int askMenu() {
    String[] menus = {"poulet", "boeuf", "végétarien"};
    int nbMenu = askSomething("menu", menus);
    return nbMenu;
}

On aurait aussi pu directement faire :

/**
 * Display a question about menu in the standard input, get response and display it
 * @return the number of the selected menu
 */
public int askMenu() {
    String[] menus = {"poulet", "boeuf", "végétarien"};
    return askSomething("menu", menus);
}

Et oui ! On peut directement faire transiter la valeur retournée par  askSomething  sans créer une variable intermédiaire.

On peut à présent modifier  runMenu .

/**
 * Run asking process for a menu.
 */
public void runMenu() {
    int nbMenu = askMenu();
    switch (nbMenu) {
        case 1:
            askSide(true);
            askDrink();
            break;
        case 2:
            askSide(true);
            break;
        case 3:
            askSide(false);
            askDrink();
            break;
    }
}

On voit immédiatement dans l'UML les méthodes qui retournent une valeur et celles qui ne le font pas :

UML avec askSomething et askMenu modifiés
UML avec askSomething et askMenu modifiés

Un double retour ?

En plus d'afficher au fur et à mesure les choix de l'utilisateur, on aimerait qu'il y ait un résumé à la fin de la commande.

En plus d'afficher du texte dans  askSomething , il faut stocker ce texte au fur et à mesure.

On sait déjà comment concaténer plusieurs chaînes de caractères entre elles :

jshell> String hello = "hello";
hello ==> "hello"

jshell> String world = "world";
world ==> "world"

jshell> hello + " " + world + "!";
$36 ==> "hello world!"

Le problème est de savoir comment récupérer la chaîne de caractères générée dans  askSomething . On pourrait simplement retourner cette chaîne comme ceci :

/**
 * Display a question about a category in the standard input, get response and display it
 * @param category the category of the question
 * @param responses available responses
 * @return the sentence displayed of the selected choice
 */
public String askSomething(String category, String[] responses) {
        System.out.println("Choix " + category);
        for (int i = 1; i <= responses.length; i++)
            System.out.println(i + " - " + responses[i - 1]);
        System.out.println("Que souhaitez-vous comme " + category + "?");
        int nbResponse;
        boolean responseIsGood;
        do {
            nbResponse = sc.nextInt();
            responseIsGood = (nbResponse >= 1 && nbResponse <= responses.length);
            if (responseIsGood) {
                String choice = "Vous avez choisi comme " + category + " : " + responses[nbResponse - 1]
                System.out.println(choice);
            } else {
                boolean isVowel = "aeiouy".contains(Character.toString(category.charAt(0)));
                if (isVowel)
                    System.out.println("Vous n'avez pas choisi d'" + category + " parmi les choix proposés");
                else
                    System.out.println("Vous n'avez pas choisi de " + category + " parmi les choix proposés");
            }
        } while (!responseIsGood);
        return choice;
}

Mais là, c'est notre modification du début de chapitre qui ne va plus fonctionner.

Il faudrait pouvoir renvoyer plusieurs types : un  String  ET un  int. Ce n'est pas possible ! On doit retourner toujours un seul et unique type !

On va voir comment résoudre ce type de problématique avec un attribut.

Un nouvel attribut

Pour rappel un attribut représente un composant dans une classe. Pour savoir si une variable est attribut, il faut se poser les questions suivantes :

  • Est-ce que ma variable représente un composant de mon objet ?

  • Est-ce que j'ai besoin de cette variable uniquement dans une méthode ou dans plusieurs ?

Dans notre situation, c'est le cas. Le résumé d'une facture est un composant de celle-ci. Nous en avons besoin dans plusieurs méthodes.

On va ajouter un nouvel attribut de type  String  nommé  orderSummary . Voici le résultat attendu :

Combien souhaitez vous commander de menu ?
1
Choix menu
1 - poulet
2 - boeuf
3 - végétarien
Que souhaitez-vous comme menu?
2
Vous avez choisi comme menu : boeuf
Choix accompagnement
1 - légumes frais
2 - frites
3 - riz
Que souhaitez-vous comme accompagnement?
2
Vous avez choisi comme accompagnement : frites

Résumé de votre commande:
Menu 1:
Vous avez choisi comme menu : boeuf
Vous avez choisi comme accompagnement : frites

Voilà comment cela va fonctionner :

  • Par défaut le contenu de  orderSummary  est  "Résumé de votre commande:%n" .

  •  Pour chaque menu demandé,  runMenus  va y ajouter, le menu courant  "menu 1:%n" ,  "menu 2:%n" , etc.

  • À chaque fois que  askSomething  est utilisé il va ajouter du texte à  orderSummary  en plus de l'afficher :  "Vous avez choisi comme menu : poulet%n"  .

  • On va recommencer pour chaque menu demandé.

  • À la fin  runMenus  affiche le contenu de orderSummary  :  System.out.println(String.format(orderSummary)); .

À quoi servent  %n  et  String.format  ?

Je vous l'ai dit sur Windows, sur Linux et sur Mac OS X, le retour à la ligne ne s'affiche pas de la même façon.

Il y a un mécanisme prévu dans Java pour gérer pour ce problème. En mettant  %n  dans une variable  String  puis en utilisant  String.format  sur cette variable, cela va automatiquement transformer  %n  en  \n  ou  \r\n  selon le système d'exploitation.

On va commencer par ajouter de nouveaux tests :

@Test
public void Given_Response_When_CallingAskQuestion_Then_FillOrderSummaryCorrectly() {
    System.setIn(new ByteArrayInputStream(String.format("1%n").getBytes()));
    order = new Order();
    String[] responses = {"BMW", "Audi", "Mercedes"};
    int choice = order.askSomething("voiture", responses);
    assertEquals("Vous avez choisi comme voiture : BMW%n", order.orderSummary);
}
@Test
public void Given_Responses_When_CallingRunMenus_Then_FillOrderSummaryCorrectly() {
    System.setIn(new ByteArrayInputStream(String.format("2%n1%n1%n1%n2%n2%n").getBytes()));
    order = new Order();
    order.runMenus();
    assertEquals("Résumé de votre commande :%n" +
            "Menu 1:%n" +
            "Vous avez choisi comme menu : poulet%n" +
            "Vous avez choisi comme accompagnement : légumes frais%n" +
            "Vous avez choisi comme boisson : eau plate%n" +
            "Menu 2:%n" +
            "Vous avez choisi comme menu : boeuf%n" +
            "Vous avez choisi comme accompagnement : frites%n" , order.orderSummary);
}

Voici le code modifié.

public class Order {
    Scanner sc = new Scanner(System.in);
    String orderSummary = "";
    
    ...
    
    /**
     * Run asking process for several menus.
     */
    public void runMenus() {
        System.out.println("Combien souhaitez vous commander de menu ?");
        int menuQuantity = sc.nextInt();
        orderSummary = "Résumé de votre commande :%n";
        for (int i = 0; i < menuQuantity; i++) {
            orderSummary += "Menu " + (i + 1) + ":%n";
            runMenu();
        }
        System.out.println("");
        System.out.println(String.format(orderSummary));
    }
    
    ...
    
    /**
     * Display a question about a category in the standard input, get response and display it
     * @param category the category of the question
     * @param responses available responses
     * @return the number of the selected choice
     */
    public int askSomething(String category, String[] responses) {
        System.out.println("Choix " + category);
        for (int i = 1; i <= responses.length; i++)
            System.out.println(i + " - " + responses[i - 1]);
        System.out.println("Que souhaitez-vous comme " + category + "?");
        int nbResponse;
        boolean responseIsGood;
        do {
            nbResponse = sc.nextInt();
            responseIsGood = (nbResponse >= 1 && nbResponse <= responses.length);
            if (responseIsGood) {
                String choice = "Vous avez choisi comme " + category + " : " + responses[nbResponse - 1];
                orderSummary += choice + "%n";
                System.out.println(choice);
            } else {
                boolean isVowel = "aeiouy".contains(Character.toString(category.charAt(0)));
                if (isVowel)
                    System.out.println("Vous n'avez pas choisi d'" + category + " parmi les choix proposés");
                else
                    System.out.println("Vous n'avez pas choisi de " + category + " parmi les choix proposés");
            }
        } while (!responseIsGood);
        return nbResponse;
    }
    
    ...
    
}

 On ajoute du contenu à  orderSummary  au fur et à mesure et on l'affiche à la fin.

Dans le prochain chapitre, on va voir comment gérer toutes les erreurs de notre programme !

Exemple de certificat de réussite
Exemple de certificat de réussite