Sujet du TD 2 2324
Objectifs
Ce TD est appelé TD2 non pas parce-que c'est le
deuxième, mais parce qu’il appartient à la séquence 2; il peut être découpé en
TD2.1 et TD2.2.
Il a pour but de vous entraîner à écrire sur papier (comme en contrôle)
une classe complète, avec ses attributs et ses méthodes. La javadoc n’est pas demandée.
Pour chaque exercice, lire les 2 parties Q(uestion) et R(éponse) avant de commencer à le résoudre.
Quelques
rappels
- Une classe
(ex: Cercle) possède des attributs (ex: aDiametre) d'un certain type (ex: int).
- Un constructeur permet d'initialiser les attributs,
soit à des valeurs fixées dans ses instructions, soit à des valeurs qu'on lui
passe en paramètres (entre les parenthèses). Il ne comporte aucun mot entre public et son nom (qui doit être identique à celui de la classe). Il est appelé
automatiquement à la création de chaque objet de sa classe.
- Une procédure (ex: vaDroite) ne retourne rien, ce qui est indiqué dans sa
définition par le mot void entre public et le nom de la procédure.
- Mais on peut aussi définir une fonction qui retourne
toujours une et une seule valeur, dont le type doit être précisé entre public et le nom de la fonction. Ses instructions se terminent toujours par un return suivi de la valeur qu'elle retourne.
- Lorsqu'il n'y a pas de paramètres, tant la
définition que l'appel d'une fonction, d'une procédure, ou d'un constructeur se
termine quand-même obligatoirement par ().
- On notera que la classe Cercle possède ainsi deux méthodes de même nom : Cercle. Ceci ne crée pas d'ambiguïté car ces deux méthodes ont des signatures
différentes. Cette possibilité qu'offre Java est appelée surcharge.
- a = b % c; met
dans a le reste de la division entière de b par c, alors que a = b / c; met dans a le quotient
de la division entière de b par c. % est l’opérateur souvent appelé « modulo ».
- le + appliqué à
une String permet de lui concaténer la représentation textuelle
de n’importe quel objet ou nombre.
- ne pas confondre l’affectation a = b; qui change la valeur de a, avec la comparaison a == b qui vaut vrai ou faux, mais qui ne
modifie rien.
- l’instruction
SI condition_est_vraie ALORS instructions_1 SINON instructions_2
FINSI se traduit par :
if (condition) { instructions_1 }
else { instructions_2 }
- Un appel récursif survient quand une méthode
s'appelle elle-même (avec une valeur de paramètre qui a changé).
- Il est
possible d’afficher les valeurs de vos variables avec System.out.println(…);
- Ci-après, le code java (corrigé) de MaPremiereClasse pour pouvoir vous en inspirer.
* dans le sujet suivant signale
un apport de connaissance, à apprendre comme les encadrés rouges du cours !
Ma première
classe
public class MaPremiereClasse // nom peu
intéressant pour une vraie classe
{
// ###
Attributs ###
private
int aPremierAttribut; // noms
private
boolean aDeuxiemeAttribut; // peu intéressants
private
String aTroisiemeAttribut; // pour des
vrais attributs
// ###
Constructeurs ###
/**
* Construit
toujours le meme objet : 2, true, "exemple"
*/
public
MaPremiereClasse()
{
this.aPremierAttribut = 2;
this.aDeuxiemeAttribut = true;
this.aTroisiemeAttribut = "exemple";
} //
MaPremiereClasse()
/**
*
Constructeur naturel
* @param pI
entier pour initialiser aPremierAttribut
* @param pB
booleen pour initialiser aDeuxiemeAttribut
* @param pS
chaine pour initialiser
aTroisiemeAttribut
*/
public MaPremiereClasse( final int pI, final
boolean pB, final String pS )
{
this.aPremierAttribut = pI;
this.aDeuxiemeAttribut = pB;
this.aTroisiemeAttribut = pS;
} //
MaPremiereClasse()
// ###
Accesseurs ###
public
int getPremierAttribut() { return this.aPremierAttribut; }
public boolean getDeuxiemeAttribut() { return this.aDeuxiemeAttribut; }
public String getTroisiemeAttribut()
{ return this.aTroisiemeAttribut; }
// ###
Modificateurs ###
public void
setPremierAttribut( final int pPremierAttribut )
{
this.aPremierAttribut =
pPremierAttribut; }
public void
setDeuxiemeAttribut( final boolean
pDeuxiemeAttribut )
{ this.aDeuxiemeAttribut = pDeuxiemeAttribut; }
public void
setTroisiemeAttribut( final String
pTroisiemeAttribut )
{
this.aTroisiemeAttribut = pTroisiemeAttribut; }
// ### Autres
methodes ###
/**
* Un exemple
de procedure (qui ne retourne rien)
*/
public void procedure()
{
String vEspace = " "; // variable
locale
System.out.println( "La procedure” +
vEspace + "s'est bien executee." );
// l’instruction
System.out.println(x); affiche x dans la
fenêtre Terminal *
return; // facultative
dans une procédure
} // procedure()
/**
* Un exemple de fonction booleenne
* @return
toujours true
*/
public boolean
fonction()
{ return true; }
} // MaPremiereClasse
I. La classe
Q: On souhaite pouvoir représenter et manipuler un
nombre rationnel, c'est-à-dire une fraction (le rapport entre deux
entiers). Créer la classe nécessaire (vide, pour l'instant).
R: Le mot souligné dans la question ci-dessus paraît
adapté comme nom de classe. Donc, écrire en java le début et la fin de cette
classe (attention aux conventions de
nommage). Entre les deux, nous écrirons ensuite tous les attributs et
toutes les méthodes.
II. Les attributs
Q: Un nombre rationnel est composé de deux nombres
entiers appelés numérateur et dénominateur. Créer (c'est-à-dire
déclarer) les attributs nécessaires.
R: Les mots soulignés dans la question ci-dessus
paraissent adaptés comme noms d'attributs (pour aller plus vite, on peut
choisir de ne conserver que les 3 premières lettres). Le type de ces
attributs étant précisé dans la question, écrire en java la déclaration de ces
2 attributs (attention aux conventions de nommage).
III. Les constructeurs
Q: Écrire le constructeur naturel (qui possède autant de
paramètres qu'il y a d'attributs *).
Le cas dénominateur nul sera traité plus
tard.
R: Il s'écrit toujours de la même façon, tant sa
signature (attention aux conventions de nommage) que son corps.
Q: Écrire un deuxième constructeur (quelconque),
à un seul paramètre, que l'on utilisera pour créer un nombre rationnel
lorsqu'il a la particularité d'être égal à un nombre entier. Donc à
quoi correspond ce paramètre ?
(par exemple, quel est le plus
simple rationnel – numérateur & dénominateur – qui vaut 12 ?).
R: Dans ce cas, nul besoin de préciser en paramètre la
valeur du dénominateur : nous la connaissons déjà ! Par exemple, si le rationnel vaut 5, que valent son numérateur
et son dénominateur (au plus simple) ?
v1) Comme le rôle d'un constructeur est toujours le même, une première
idée serait de recopier et adapter les instructions du constructeur naturel que
nous avons déjà écrit (faites-le !).
v2) Mais comme la duplication de code est l'ennemi public
numéro un en programmation, nous REMPLACERONS ces 2 instructions par une
seule, celle qui permet à un constructeur d'en appeler un autre dans la même
classe (en lui passant bien les paramètres qu'il attend) :
this( liste_des_valeurs_que_le_constructeur_appelé_attend_en_paramètres
); *
Attention ! Cette instruction ne peut être écrite qu'en première
instruction d'un constructeur. *
v3) Comme nous ne savons pas comment signaler une erreur dans un
constructeur, modifier le 1er constructeur pour qu’il crée le
rationnel 0 lorsqu’on lui passe un dénominateur nul.
IV. Les accesseurs et les modificateurs *
En anglais, Ils sont appelés getters
and setters car les premiers commencent toujours par get et les seconds toujours par set. Ces
méthodes sont utilisées principalement quand on est à l’extérieur de la classe.
Q: Écrire les accesseurs (pour accéder -- en lecture
-- à un attribut).
R: Vous savez combien ils sont (d'après le nombre
d'attributs), comment ils s'appellent (d'après le nom de l'attribut),
si ce sont des fonctions ou procédures (doit retourner la valeur de
l'attribut), quels sont leurs paramètres (aucune information
supplémentaire n'est nécessaire pour accomplir leur tâche), et quelle
instruction ils contiennent (rôle simple et unique). Si ce n'est pas le cas, demandez à
un intervenant (c'est là que se situe la différence avec un contrôle ...)
Q: Écrire les modificateurs (pour modifier la valeur
d'un attribut).
R: Vous savez combien ils sont (d'après le nombre d'attributs),
comment ils s'appellent (d'après le nom de l'attribut), si ce sont des
fonctions ou procédures (doit modifier la valeur de l'attribut sans
retourner de résultat), quels sont leurs paramètres (il faut bien
préciser la valeur qu'on souhaite mettre dans l'attribut), et quelle
instruction ils contiennent (rôle simple et unique). Si ce n'est pas le cas, demandez à
un intervenant (c'est là que se situe la différence avec un contrôle ...)
V. Deux fonctions à définir dans la plupart des classes
Q: Écrire la fonction toString qui retourne une String représentant au mieux le rationnel
courant ; elle n'a besoin d'aucun paramètre. Cette fonction sera évidemment
appelée à chaque fois qu'on aura besoin d'afficher un nombre rationnel, comme
par exemple 3 fois si on souhaite afficher cette égalité : 1/3 + 1/6 = 1/2.
Attention ! Cette fonction ne doit en aucun cas modifier le rationnel
courant.
R: 1) Écrire une première version simple qui ne tient
compte d'aucun cas particulier, c'est-à-dire qui se contente de retourner le
numérateur suivi d'un / suivi du dénominateur.
+ Il faut
donc ici construire une chaîne de caractères à partir de plusieurs morceaux (le
numérateur, le /, et le dénominateur). En java, l'opérateur de concaténation (mise
bout à bout) de chaînes de caractères est tout simplement le +. En outre, si vous écrivez uneChaine+unEntier, alors unEntier
est automatiquement converti en chaîne de caractères avant d'être concaténé à uneChaine. "" (chaîne
vide) est différente de "
" (un
espace).
EN TRAVAIL PERSONNEL (ou pendant le TD, s’il reste du temps à la fin) :
2) Ajouter 2 cas particuliers
(indépendants) : a) le numérateur est nul (donc peu importe le dénominateur)
et b) le dénominateur vaut 1 (donc inutile
de l'afficher).
3) Ajouter enfin ce qu'il faut pour
qu'un dénominateur ne soit jamais négatif (on préfère -1/3 à 1/-3).
Q: Écrire la fonction booléenne egal qui retourne Vrai ou Faux selon que le rationnel (passé en unique
paramètre) est égal ou non au rationnel courant (un produit en croix ?).
A noter : on peut utiliser le type
Rationnel à l’intérieur de la classe Rationnel. *
R: Le type retourné, le nom et le paramètre sont
indiqués dans la question. Il faut maintenant déterminer à quelle condition on
peut affirmer que 2 rationnels sont égaux : ce n'est pas simplement « leurs
numérateurs sont égaux et leurs dénominateurs sont égaux » car 1/3 est
égal à 2/6 par exemple. Le produit croisé semble ici le plus simple à écrire
(1x6 est bien égal à 2x3). Mais au fait, peut-on bien accéder aux numérateurs
et dénominateurs des 2 rationnels à comparer ? La réponse est oui :
+ La
protection assurée par private ne se situe pas autour de chaque
objet, mais autour de la classe, ce qui permet à une méthode appelée sur un
objet d'accéder aux attributs privés d'un autre objet de cette même classe.
R2 : Si vous avez utilisé un if , réfléchissez à la façon dont on pourrait totalement s’en passer !?
(ce qu’on appelle une condition est une simple valeur booléenne…)
VI. Autres méthodes
Q: Écrire la fonction add qui retournera le rationnel égal à la somme du rationnel courant avec le
rationnel passé en paramètre (sans simplification). Par exemple, l'ajout d' 1/3
à 1/6 retournera le nouveau rationnel 9/18.
R: Le type retourné, le nom et le paramètre sont
indiqués dans la question. Il faut évidemment calculer le numérateur et le
dénominateur du rationnel résultat de cette addition, et retourner un nouveau
rationnel créé avec ces 2 valeurs calculées. Aide : Vous vous rappelez de new Cercle() dans BlueJ ?
Q: Écrire une procédure simplification du Rationnel courant,
qui par exemple, transformera 12/18 en 2/3. A-t-elle
besoin d’informations supplémentaires ?
R: Pour ne pas avoir à faire de
boucle, on divisera simplement en haut et en bas par le PGCD (il faut créer
cette fonction auxiliaire dans la classe Rationnel). Si la simplification fonctionne bien, il peut
être intéressant de l'appeler automatiquement à la fin de add et aussi à la fin du constructeur naturel.
Donc créer et utiliser une fonction
récursive (sans boucle !) pour calculer le PGCD :
- pgcd( a,
0 ) à a
- pgcd( a, b ) à pgcd( b,
a modulo b
) Que donne
cette formule si b>a ?
|
VII. Autres classes
Q: Comment tester/utiliser la nouvelle classe qui vient
d'être écrite ci-dessus ?
R: Créer une classe Utilisation sans
attributs avec une seule procédure essai sans aucun
paramètre qui créera des rationnels dont vous choisirez judicieusement les valeurs, et qui testera toutes les méthodes.