CSI1502 Principes fondamentaux en conception des logiciels Chapitre 4 Classes et Objets
Objectifs du cours: Comprendre ce qui suit: Un objet, son état et sa fonction Définitions de classe Encapsulation et modificateur d`accès Au sujet de méthodes: Déclaration de méthodes, invocation, et passage des valeurs Surcharge de méthode Decomposition de méthode Relation entre objets et agrégation Objets graphiques
Que’est-ce que un objet? Un état: caractéristiques descriptives Une fonction: ce que l`objet peut faire ou ce qui peut être fait à l`objet Par exemple considérons une pièce de monnaie utilisé dans un pile ou face L`état de la pièce est soit pile, soit face La fonction de la pièce est de se faire tourner aléatoirement afin d`atteindre un nouvel état
Que’est-ce que une classe? Une classe est le plan d`un objet C`est un modèle à partir du quel les objets sont crées Par exemple la classe String est utilisé pour définir les objets String Chaque objet String contient des caractères spécifiques (son état) Chaque objet String peut performer des fonctions tel que toUpperCase Nous pouvons aussi écrire nos propres classes qui définissent des objets dont on à besoin L`on peut écrire une classe pièce de monnaie pour représenter un objet pièce de monnaie
Plus au sujet des classes Une classe contient des déclarations de donnés et des déclarations de méthodes int x, y; char ch; Déclarations de variables Déclarations de méthodes
Exemple: Une classe pièce de monnaie Variables: face, un int représentant l’état courant PILE et FACE des int constant représentant la valeur des deux états Méthodes: pieceDeMonnaie, un constructeur pour initialiser l`objet tourne, une méthode pour faire tourner la pièce de monnaie estFace, une méthode pour déterminer si l`état courant est face toString, une méthode qui retourne un String descriptif pour afficher les résultats
L`exemple de la pièce de monnaie: PileOuFace.java // Demonstration de l`utilité de classe définie par le programmeur public class CompteurDeTour { // public static void main (String[] args) final int NOMBRE_DE_TOURS = 1000; int face = 0, pile = 0; pieceDeMonnaie maPiece = new pieceDeMonnaie(); // initialise l`objet pieceDeMonnaie Continué…
L`exemple de la pièce de monnaie: PileOuFace.java (cont.) for (int compte = 1; compte <= NOMBRE_DE_TOURS; compte ++) { maPiece.tourne( ); if (maPiece.estFace()) { face++; } else { pile++; } System.out.println(“ Nombre de tours ” + NOMBRE_DE_TOURS); System.out.println(“ Nombre de face ” + face); System.out.println(“ Nombre de pile ” + pile);
L`exemple de la pièce de monnaie: PieceDeMonnaie.java public class pieceDeMonnaie { public final int FACE = 0; public final int PILE = 1; private int etat; // --------------------------------------------- // Crée l`état initiale de la pièce en la tournant au début. // public pieceDeMonnaie(){ tourne(); } Continué…
L`exemple de la pièce de monnaie: PieceDeMonnaie.java // ----------------------------------------------- // Tourne la pièce aléatoirement. // public void tourne() { etat = (int) (Math.random() * 2); } // ----------------------------------------------------- // Retourne vrai si l`état courant et face. public boolean estFace() { return (etat == FACE); Continué…
L`exemple de la pièce de monnaie: PieceDeMonnaie.java // --------------------------------------------------- // Retourne l’état courant de la pièce sous la forme d`un objet String // public String toString(){ String NomDeLEtat; if (etat == FACE) { NomDeLEtat = "Face"; } else { NomDeLEtat = "Pile"; } return NomDeLEtat;
Un exemple: Exécution de PileOuFace Première exécution: Nombre de tours 1000 Nombre de face 493 Nombre de pile 507 Deuxième exécution: Nombre de face 514 Nombre de pile 486
L`outrepassement des méthodes: Un exemple (Overriding en Anglais) En rajoutant le code suivant dans la classe pieceDeMonnaie ce code marche: public static double random() { System.out.println("Mon système aléatoire"); return 0; } L`on ne peut ajouter cette méthode dans la classe Math Actuellement vous pouvez être poursuivie légalement par Sun pour modification ou extension, des Paquets, APIs, Classes ou Méthodes crées par eux Sun à les droits intellectuels sur Java
Avantages et désavantages des classes et méthodes statiques Rappel: vous n`avez pas besoin d`utiliser new pour créer un objet Ils restent dans le système même si vous en avez pas toujours besoin Ils ne sont pas géré d`une façon efficace par le collecteur d`ordure Trop des classes et méthodes statiques peuvent ralentir vôtre application Elles forment un “héritage” de C++ et n`ont pas vraiment leur place dans le paradigme orienté objet
Discussion: La classe PieceDeMonnaie Notez que le programme CompteurDeTour n`a pas utilisé la méthode toString Un programme ne va pas toujours utiliser tous les fonctions d`un objet Une fois que la classe pieceDeMonnaie a été définie nous pouvons dorénavant l`utiliser dans d`autres programmes
La portée et les instances des variables La portée des variables est la zone dans laquelle nous pouvons utiliser ces variables Des variables initialisées au niveau de la classe peuvent être utilisé dans toute la classe Des variables initialisées dans une méthode ne peuvent être utilisé que dans cette méthode
Les variables d`instance La variable etat dans la classe pieceDeMonnaie est appelé une variable d`instance car chaque instance (objet) de la classe pieceDeMonnaie à son propre état. Une classe déclare le type de variable, mais ne réserve pas d`espace en mémoire pour la variable. Pour chaque pieceDeMonnaie qui est crée, une variable etat est aussi crée Les Objets d`une même classe partagent les définitions de méthodes, mais chacun garde son propre espace de variable C`est la seule façon qui permet a deux objets d`avoir des états différents
Les variables d`instance Voir FlipRace.java (page 217) Pièce de Monnaie 1 int etat; etat 1 Pièce de Monnaie 2 etat
Diagramme UML UML est le “Unified Modelling Language” Les diagrammes UML montrent les relations entre les classes et les objets Un diagramme UML consiste de une ou plusieurs classes avec des sections pour le noms des classes, attributs et méthodes Les lignes entre les classes représentent les associations Les Associations peuvent montrer la multiplicité
Diagramme UML de classe Un diagramme UML pour le programme FlipRace: FLIP RACE COIN 1 2 face : int main (args : String[]) : void flip() : void isHeads() : boolean toString() : String
Diagramme UML Un diagramme UML d`objet consiste d`au moins un objet initialisé C`est un projection des objets durant l`exécution du programme, montrant les variables coin1 : Coin coin2 : Coin face = 0 face = 1
Propriétés des objets: Encapsulation L’on peut voir un objet de deux façons: Interne – Les variables de l’objet et les méthodes qui rendent l’objet utile Externe – Les services que l’objet offre et comment l’objet interagit. Du point de vue externe l’objet est une entité encapsulée, offrant des service spécifiques Ces services définissent l`interface d`un objet Nous avons dans le chapitre 2 que l`objet est une abstraction, cachant des détails au reste du système
Plus au sujet de l`encapsulation Un objet devrait être autonome Tout changement à l`état d`un objet (ses variables) devrait être fait au travers de ses méthodes L`on devrait rendre l`accès au variables difficile, si pas impossible, d`une autre façon qu`au travers de ses méthodes L`utilisateur, ou client, doit être en mesure d`utiliser les services d`un objet, mais sans avoir besoin de savoir comment ceux-ci sont accomplis
Plus au sujet de l`encapsulation L`on doit penser à un objet encapsulée comme une boîte noire, dont le client ne connaît que les méthodes d`interface Méthodes Client Variables
Les modificateur d`accès En Java nous pouvons accomplir l`encapsulation au travers l`usage des modificateur d`accès Modificateur (ou modifier en Anglais) est un terme réservé en Java qui spécifié les caractéristiques particulières d`une méthode ou de variable Nous avons utilisé le modificateur final pour définir une constante Java a trois modificateur d`accès: public, protected et private Le modificateur protected implique certains aspects d`héritage, que nous allons voir plus tard
Les modificateur d`accès Les membres d`une classe avec un modificateur d`accès public sont accessible de partout Les variables public violent l`encapsulation Les membres d`une classe avec un modificateur d`accès private ne sont accessible que de l`intérieur d`une classe Les membres d`une classe sans un modificateur d`accès sont accessible sont accessible de tous les classes dans le même paquet Les modificateurs Java sont discuté en détails dans l`appendice F
Les modificateur d`accès Les méthodes qui fournissent les services d`un objet sont usuellement déclaré avec un modificateur public de façon à être utilisé par les clients Les méthodes publiques sont aussi appelés des méthodes de service Une méthode crée pour aider une méthode de service est une méthode de support Les méthodes de support ne devraient pas avoir de modificateur d`accès public
Les modificateur d`accès public private Viole l`encapsulation Renforce l`encapsulation variables Fourni les services aux clients Supporte les autres méthodes de la classe méthodes
Programme contrôleur Le programme contrôleur, contrôle les autres parties plus intéressantes d`un programme Le programme contrôleur sont souvent utilisé pour tester d`autres parties d`un programme Le Banking class contient une méthode main, qui contrôle l`usage de la classe Account, utilisant ses services Voir Banking.java (p. 226) Voir Acount.java (p. 227)
Programme contrôleur: Banque.java public class Banking { // crée des comptes de banque et utilise des services public static void main (String[] args) { Account acct1 = new Account("Joe Smithfield", 2341, 200.00); Account acct2 = new Account("Sue Smith", 3212, 1300.01); acct1.deposit(23.43); double smithBalance = acct2.deposit(500.00); System.out.println("Solde de Smith " + smithBalance); acct1.addInterest(); System.out.print("Nouvelle solde de Smithfield "); System.out.println(acct1.getBalance()); }
Programme contrôleur: Comptes.java public class Account { private final double RATE = 0.035; // taux d`interêt de 3.5% private long acctNumber; private double balance; private String name; // Constructeur de classe, initialise les variables public Account (String owner, long account, double initial) { name = owner; acctNumber = account; balance = initial; } Continué…
Programme contrôleur: Comptes.java (cont.) public double deposit (double amount) { if (amount < 0) // si la valeur déposée est négative { System.out.println("Erreur: dépôt invalide."); } else { balance = balance + amount; return balance; } public double addInterest() { balance += (balance * RATE); public double getBalance() {
Les resultats: Banque et Comptes Solde de Smith 1800.01 Nouvelle solde de Smithfield 231.25 Remarques: La variable balance est private, nous ne pouvons y accéder directement, nous utilisons une méthode Voir page 227-229 pour tout le programme Il utilise la classe NumberFomat pour formater les resultats
Déclaration de méthode Une déclaration de méthode spécifie le code qui va être exécuté quand la méthode va être invoquée Quand une méthode est invoquée le contrôle est passé à la méthode et le code exécuté Une fois l`exécution terminée le contrôle retourne la d`ou la méthode à été invoquée L`invocation peut ou ne peut pas retourner de valeur selon la façon dont la méthode a été définie
Contrôle d`une méthode La méthode invoqué peut-être dans la même classe dans quel cas on a juste besoin de la nommer Exécution MaMethode() MaMethode();
Contrôle d`une méthode La méthode invoqué peut-être aussi dans une autre classe ou objet MaClasse main MaClasse.MaMethode(); MaMethode() AideMoi() AideMoi();
L`en-tête de la méthode La déclaration d`une méthode commence avec son en-tête char calc (int num1, int num 2, String message){ Liste de paramètres La liste de paramètres spécifie le type de chaque et chacun des paramètre nom de la méthode Le nom d`un paramètre dans la déclaration d`une méthode est un argument formel Type de la Valeur retourné
Le corps de la méthode L`en-tête d`une méthode est suivie par le corps { int sum = num1 + num2; char result = message.charAt (sum); return result; } sum et result sont des variables locales Ils sont crées a chaque fois que la méthode Est invoqué et détruit à la fin de l`exécution La valeure retourné doit-être le même type que le type de la Valeur retourné
La valeur de retour Le type de la valeur retourné indique la valeur que la méthode retourne à l`origine de l`invocation Une méthode qui ne retourne pas de valeur a un type de la valeur void L`expression de retour spécifie ce qui est retourné: return expression; L`expression retourné doit conformer au type de la valeur de retour
Paramètres d`une méthode Pour chaque invocation d`une méthode les paramètres de l`invocation sont copiés dans les paramètre formels resultat = obj.calc(25, count, “Allo”) char calc (int num1, int num2, String message) { int sum = num1 + num2; char result = message.charAt (sum); return result; }
Variables locales d`une méthode Variables locales peuvent être déclarées dans une méthode Les paramètre formels de la méthode créent des variables locales automatiquement quand la méthode est invoquée Quand la méthode a fini d`exécuter toutes les variables locales sont détruite (incluant les paramètre formels) Il s'agit de ce rappeler que les variables d`instance crées au niveau de la classe existent tant et aussi longtemps que la classe existe Toute méthode dans la classe peut référer au variables d`instance
Retour au constructeurs Les constructeurs sont des méthodes spéciale qui initialisent les objets nouvellement crées En écrivant un constructeur: Il a le même nom que la classe Il n`y a pas de valeur de retour Il n`y a pas de type de la valeur de retour même pas void Typiquement initialise les variables a leur valeurs de défaut Le programmeur ne doit pas nécessairement définir un constructeur pour un classe
La surcharge d`une méthode La surcharge d`une méthode est un processus qui consiste a utiliser le même nom d`une méthode pour différentes méthodes La signature de chaque méthode surchargée doit être unique La signature inclus le nombres, type, ordre des paramètre d`une méthode Le compilateur détermine quelle version des paramètre est invoqué à partir des paramètres Le type de la valeur retourné ne fait pas partie de la signature
resultat = obj.testMoi(25, 4.32); Méthodes surchargées version 1 float testMoi(int x){ return x + .375; } version 2 float testMoi(int x, float y){ return x*y; } invocation resultat = obj.testMoi(25, 4.32);
Méthodes surchargées Les méthodes print()/println() est surchargée println (String s) println (int i) println (double d) etc... Le code suivant invoque plusieurs differentes versions des méthodes print()/println(): System.out.println ("Le total est: "); System.out.println (total +".");
Constructeurs surchargés: SnakeEyes.java public class SnakeEyes { // Fait rouler les dés et compte les double 1 public static void main (String[] args) { final int ROLLS = 500; int snakeEyes = 0, num1, num2; Die die1 = new Die(); //creates a 6-sides die Die die2 = new Die(20); //creates a 20-sides die for (int rols = 1; rols <= ROLLS; rols++){ num1 = die1.roll(); num2 = die2.roll(); if (num1 == 1 && num2 ==1){ snakeEyes++; } System.out.println("Nombre de Snake Eyes " + snakeEyes);
Constructeurs surchargés: Die.java public class Die { private final int MIN_FACES = 4; private int numFaces; //nombre de face sur un dé private int faceValue;// valeur courante du dé // constructeur par défaut: 6 faces, valeur initiale du dé est 1 public Die() { numFaces = 6; faceValue = 1; } Continué…
Constructeurs surchargés: Die.java (cont.) // determine la taille du dé // met le défaut à 6 si valeur invalide public Die (int faces) { if (faces < MIN_FACES){ numFaces = 6; }else{ numFaces = faces; } faceValue = 1; Continué…
Constructeurs surchargés: Die.java (cont.) //fais rouler le dé et retourne le résultat public int roll() { faceValue = (int) (Math.random() * numFaces) + 1; return faceValue; } // Retourne la valeur courante du dé public int getFaceValue () {
Trucs pour écrire des méthodes: Décomposition de méthode Une méthode devrait être assez petite afin de faciliter la compréhension de sa fonction Une méthode complexe devrait être décomposé en plusieurs petites méthodes afin de clarifier la fonction Une méthode de service peut appeler une ou plusieurs méthodes de support pour accomplir sa fonction Une méthode de support peut en appeler d`autre si l`on a en besoin
Exemple de “pig latin”: “happy” devient “appyhay” Par exemple le processus de transformer une phrase en anglais en “pig latin” peut-être décomposé en processus de traduire chaque mot individuellement Le processus de traduire chaque mot peut-être décomposé en le processus de traduire les mots qui : commencent avec des voyelles commencent avec des consonantes etc… Voir PigLatin.java (p.238) et PigLatinTranslator.java (p.240)
Retour aux diagrammes de classe Dans un diagramme UML les méthodes publiques peuvent être précédé par un + De même les méthodes privées peuvent être précédé par un – Un diagramme UML du programme PigLatinTranslator.java PigLatin PigLatinTranslator 1 1 + main (args : String[]) : void + translate (sentence : String) : String - translateWord (word : String) : String - beginsWithVowel (word : String) : boolean - beginsWithBlend (word : String) : boolean
Relations entre Objets Les objets ont différents types de relations entre l`un et l`autre Une association générale tel que dans les diagrammes UML et une relation d`utilité Une association générale indique qu`un objet (ou classe) utilise ou relie à un autre objet (ou classe) d`une certaine façon L`on devrait annoter la relation dans les diagrammes UML pour indiquer la nature de la relation écrit Auteur Livre
Relations entre Objets: Exemple des chiffres rationnels Une association peut arriver entre deux objets de la même classe Par exemple considérons certains objets de chiffres rationnels Rational r1 = new Rational(6, 8); Rational r2 = new Rational(1, 3); Rational r3, r4, r5; r3 = r1.add(r2); r4 = r1. subtract(r2); R5 = r1.divide(r2); L`objet r1 exécute une méthode et l`autre objet r2 est passé comme paramètre
Relations entre Objets: Comment ”add” marche public int getDenominator() { return denominator; } public Rational add (Rational op2) { // le calcul int commonDenominator = demonimator * ops.getDenominator(); int numerator1 = numerator + ops.getDenominator(); int numerator2 = op2.getNumerator() * denominator; int sum = numerator1 + numerator 2; return new Rational (sum, commonDenominator);
Agrégation Un objet agrégé est un objet qui contient des références à d`autre objets Par exemple un objet compte contient une référence à un objet String (le nom du propriétaire) Un objet agrégé représente une relation a- un(e) (en anglais has-a) Un compte de banque a un nom De même un étudiant peut avoir une ou plusieurs adresses
Agrégation: Adresse étudiante public class StudentBody { public static void main(String[] args) { Address school = new Address(“Smithstreet 1”, “Ottawa”, “ON”, 1KN2); Address jHome = new Address(“Mytown 23”, Quebec”, “QC”, 231G); Student john = new Student(“John”, “Doe”, jHome, school); System.out.println(john); // utilise toString pour l`impression } Voir page 250 à 253 Le Résultat John Doe Hometown 23 Quebec QC 231 Smithstreet 1 Ottawa ON 12312
Agrégation: Etudiant.java public class Student{ private String firstName, lastName; private Address homeAddress, schoolAddress; // initialise l`objet student public Student(String first, String last, Address home, Address school) { firstName = first; lastName = last; homeAddress = home; schoolAddress = school; } public String toString() // retourne l`objet student en tant que String { String result; result = firstName + “ “ + lastName + “ “ + homeAddress + “ “ +schoolAddress; return result;
Agrégation: Adresse.java public class Address { private String streetAddress, city, province; private long zipCode; // initialise l`objet address public Address(String street, String town, String st, long zip) { streetAddress = street; city = town; province = st; zipCode = zip; } public String toString() // retourne l`objet address en tant que String { String result; result = streetAddress + “ “ + city + “ “ + province + “ “ + zipCode; return result;
Agrégation en UML Une association d`agrégation et montré par un diamant ouvert dans un diagramme UML StudentBody Student 1 2 + main (args : String[]) : void - firstName : String - lastName : String - homeAddress : Address - schoolAddress : Address + toString() : String Address - streetAddress : String - city : String - province : String - zipCode : long + toString() : String
Méthodes Applet Dans des exemples précédents nous avons utilisé la méthode paint de la classe applet afin de tracer sur un applet La classe applet a plusieurs méthodes qui sont invoquées automatiquement à un certain point dans la vie d`un applet La méthode init ne se fait qu`exécuter une seule fois quand l`applet et lancé initialement La méthode start et stop se font invoquer quand l`applet devient actif ou inactif La classe applet contient aussi d`autres méthodes qui assistent en générale à l`exécution de l`applet
Objets Graphiques Tout objet défini en écrivant une classe peut avoir des éléments graphiques Ces objets doivent simplement avoir un contexte graphique (un objet Graphics) dans lequel l`on peut tracer les éléments graphiques Un Applet peut passer son contexte graphique a n`importe quel autre objet tout comme l`on peut passer des paramètres Voir LineUp.java (p. 257) et StickFigure.java (p. 259) comment tracer un “Stick Figure”
En résumé: Ecrire vos propres classes Comprendre ce qui suit: Un objet, son état et sa fonction Définitions de classe Encapsulation et modificateur d`accès Au sujet de méthodes: Déclaration de méthodes, invocation, et passage des valeurs Surcharge de méthode Decomposition de méthode Relation entre objets et agrégation Objets graphiques