L'exemple présenté ici reprend encore une fois le projet peinture que nous avons introduit dans le cours Premières Notions et que nous avons déjà repris dans ce cours dans la partie concernant les sous-programme non évènementiels, en le réécrivant avec des procédures dans paramètres.
Cette fois-ci nous allons le réécrire en utilisant des fonctions.
Ce nouvel exemple se trouve dans le répertoire Exemple-Java-Sous-Programme/PeintureAvecFonctions. L'interface graphique est toujours la même, mis à part le titre:
Rappelons que le projet Peinture permet de calculer la surface à peindre d'une pièce rectangulaire connaissant les dimensions de la pièce (longueur, largeur), le nombre de fenêtres et le nombres de portes.
Les dimensions des fenêtres, des portes et la hauteur des murs sont des constantes (LARGEUR_FENETRE=1.4 , HAUTEUR_FENETRE=1.2, LARGEUR_PORTE=0.9, HAUTEUR_PORTE=2.1, HAUTEUR_MUR=2.5).
La dernière version (répertoire Exemple-Java-Sous-Programme/Peinture) nous avait servi à introduire les procédures. Nous n'avions alors aucune notion de variables locales, ni de paramètres. Cette version du projet avait donc été écrite en utilisant uniquement des variables globales et des procédures sans paramètres.
Pour calculer la surface à peindre à l'aide de procédures, nous avions découpé le problème en quatre sous-problèmes:
Nous avions associé une procédure à chacun de ces traitements. Voici le code de ces procédures et voici l'appel de ces procédures dans la procédure évènementielle associée au bouton Calculer.
La nouvelle version que nous allons présenter ici n'utilise au contraire aucune variable globale et effectue des calculs par l'intermédiaire de fonctions.
Voici le code de cette même procédure évènementielle dans la nouvelle version:
private void BT_CalculerActionPerformed( ...) { double LargeurPiece, LongueurPiece; int NFenetre, NPorte; double SurfacePeinture; // Lecture des données LargeurPiece = es.LireDouble (CT_Largeur); LongueurPiece = es.LireDouble (CT_Longueur); NFenetre = es.LireEntier (CT_NF); NPorte = es.LireEntier (CT_NP); // Traitement SurfacePeinture = SurfaceDesMurs (LargeurPiece,LongueurPiece) - SurfaceDesFenetres (NFenetre) - SurfaceDesPortes (NPorte); //Affichage du résultat es.Afficher(SurfacePeinture,CT_SP); }
Le calcul de la surface à peindre se fait à présent en une seule affectation. Plus précisément, il est représenté par l'expression en blanc qui appelle trois fonctions:
Voici le code de ces trois fonctions:
double SurfaceDesMurs (double LaP, double LoP ) { return 2 * (LaP + LoP) * HAUTEUR_MUR; } double SurfaceDesFenetres (int nf) { return nf * LARGEUR_FENETRE * HAUTEUR_FENETRE; } double SurfaceDesPortes (int np) { return np * LARGEUR_PORTE * HAUTEUR_PORTE; }
Une fonction se distingue d'une procédure par le fait qu'elle retourne un résultat. Pour comprendre ce que signifie "retourner un résultat", il faut voir comment l'ordinateur exécute une expression contenant des appels de fonction. Nous reviendrons là-dessus un peu plus loin.
Etant donné qu'une fonction retourne un résultat, la déclaration d'une fonction doit préciser le type du résultat retourné. Le nom de ce type doit figure dans l'entête de la fonction, juste avant son nom. Dans notre exemple, les trois fonctions déclarées retourne un résultat de type double.
D'autre part, parmis les instructions figurant dans le corps d'une fonction, il doit forcément figurer une instruction permettant de 'retourner le résultat'. En Java, cette instruction s'appelle return. Elle s'écrit de la manière suivante:
return expression ;
Lorsque cette instruction est exécutée, l'expression figurant à droite du return (ce peut être une simple variable contenant le résultat) est évaluée et sa valeur sera ensuite 'retournée'.
Notez que dans notre exemple, chaque fonction ne contient que l'instruction return. Ce n'est pas forcément vrai en général.
Voyons maintenant ce que signifie "retourner un résultat". Pour cela nous allons voir comment est évaluée l'expression contenant les appels de fonctions. Dans notre exemple, nous avons l'expression suivante:
SurfaceDesMurs(LargeurPiece,LongueurPiece) - SurfaceDesFenetres(NFenetre) - SurfaceDesPortes(Nporte);
L'expression est évaluée de gauche à droite. L'ordinateur va donc commencer par évaluer l'appel de la fonction SurfaceDesMurs. Supposons que LargeurPiece = 3.6 et LongueurPiece = 4.3.
Comme dans les appels de procédures, les paramètres formels sont remplacés par les paramètres effectifs. Donc ici, LaP va prendre la valeur 3.6 et LoP, la valeur 4.3. Puis le corps de la fonction (cliquez ici pour le voir à droite) est exécuté avec ces valeurs. La fonction effectue donc le calcul suivant:
2 * (3.6 + 4.3) * HAUTEUR_MUR;
Avec une hauteur de mur de 2.50m, cela fait 39.5m2.
A la fin de l'exécution de la fonction, va donc "retourner" 39.5 dans l'expression qui l'a appelé. Tout ce passe comme si la valeur 39.5 remplacait à présent l'appel de fonction dans cette expression. C'est à dire qu'il faut à présent évaluer l'expression:
39.5 - SurfaceDesFenetres(NFenetre) - SurfaceDesPortes(Nporte);
Mais l'évaluation de l'expression n'est pas terminée. L'ordinateur va à présent exécuter l'appel de la fonction SurfaceDesFenetres. Supposons que le nombre de fenêtres soit égal à trois.
nf, le paramètre formel de cette fonction, va donc prendre la valeur 3 et la fonction va faire le calcul suivant:
3 * LARGEUR_FENETRE * HAUTEUR_FENETRE;
Avec une largeur de fenêtre de 1.4m et une hauteur de fenêtre de 1.2m, cela donne 5.04m2.
L'instruction return retourne cette valeur dans l'expression d'appel et nous obtenons:
39.5 - 5.04 - SurfaceDesPortes(Nporte);
Ici, l'ordinateur va d'abord effectuer la différence 39.5 - 5.04. Cela fait 34.46. Nous nous retrouvons donc avec l'expression:
34.46 - SurfaceDesPortes(Nporte);
Il reste donc à évaluer l'appel de la fonction SurfaceDesPortes. Supposons deux portes. Le paramètre formel np prend la valeur 2 et la fonction effectue le calcul suivant:
2 * LARGEUR_PORTE * HAUTEUR_PORTE;
Avec une largeur de porte de 0.9m et une hauteur de porte de 2.1m, cela fait 3.78m2. En ramenant ce résultat dans l'expression de départ nous obtenons:
34.46 - 3.78;
ce qui fait 30.68m2. Vous pouvez vérifier que c'est bien le résultat affiché par le programme: