9 - La POO

La POO

Dans le cours IFT 1810, on introduit à la programmation orientée objet (POO) utilisant le langage JAVA sans aller dans les détails.

Dans notre vie quotidienne, on travaille très souvent avec des objets :

Un tableau est un objet.

On peut fabriquer (construire, instancier) un tableau par plusieurs manières :

  • Fabriquer un tableau de couleur noir, en bois, de largeur 3.25 mètre, de hauteur 1.50 mètre

  • Fabriquer un tableau de couleur blanche, en plastique dur, de largeur 2.75 mètre, de hauteur 2.15 mètre

  • etc . . .

Il faut que le tableau existe avant de parler comment travailler avec un tableau.

Que peut-on faire avec un tableau ?

  • écrire au tableau

  • laver le tableau

  • effacer le tableau

  • etc …

La POO est une nouvelle méthode de programmation se basant sur trois concepts :

L’encapsulation :

Fusionner les champs de données (les attributs) et les méthodes pour manipuler ces données dans la même capsule qui s’appelle une classe. On ajoute aussi des clauses d’accès : champs souvent privés, méthodes souvent publiques.

Pour IFT 1810, on travaille seulement à ce concept.

L’héritage :

Construire de nouvelles classes étendues de classes existences qui hérite de données et de méthodes de celles-ci. De plus on peut ajouter de nouveaux champs, de nouvelles méthodes. On étudiera ce concept dans les cours après IFT 1810 (comme IFT 1170, IFT 1166, etc . . .).

Le polymorphisme :

La capacité de se présenter sous plusieurs formes. Ce concept sera présenté dans les cours suivants de IFT 1810 .

Dans le document Java_02.doc on a étudié la classe String et plusieurs de ses méthodes. Dans ce document, on apprend comment concevoir une classe et manipuler ses objets. Ce document est utile pour le numéro C du TP3 ainsi pour quelques questions du final.

Exemple 1 :

Concevoir la classe Cercle. Instancier (construire) quelques cercles puis afficher leurs informations.

On explique en classe cet exemple.

Solution (attention au saut de ligne sous Word)

/* Fichier Ex1_Cercle
 * expliqué en classe
 * Voir aussi Ex2_Cercle
 */
class Cercle
{
   // privé => accessible SEULEMENT dans la classe Cercle
   private double rayon ;

   // un constructeur pour construire (instancier) 1 cercle
   public Cercle(double r)
   {
   	  rayon = r ;
   }

   // un autre constructeur pour construire (instancier) 1 
   // cercle
   public Cercle()
   {
   	   rayon = 1.3; // par défaut
   }

   // Math.PI : le champ "static" PI de la classe Math(ématique)
   public double perimetre()
   {
   	 // 2 x PI x rayon
   	 return 2 * Math.PI * rayon;
   }

   // PI x (rayon au carré)
   public double surface()
   {
   	 return Math.PI * rayon * rayon;
   }
   public void afficher(String message)
   {
   	  // exemple : Infos du cercle ... : rayon, perimetre puis surface
   	  System.out.printf("Infos du %s\n", message);
   	  System.out.printf(" - rayon      : %6.2f\n", rayon);
   	  System.out.printf(" - périmètre  : %6.2f\n", perimetre());
   	  System.out.printf(" - surface    : %6.2f\n\n", surface());
   }


} // fin de classe Cercle

public class Ex1_Cercle {

    public static void main(String[] args) {


          Cercle c1 = new Cercle(5.7),
                 c2 = new Cercle() , // par défaut 1.3
                 c3 = new Cercle(6.1);

          // forme d'accès #1 :

          c1.afficher("cercle c1");
          c2.afficher("deuxième cercle");
          c3.afficher("cercle c3");


    } // fin de main
}// fin de Ex1_Cercle
/* Compilation et Exécution:
--------------------Configuration: <Default>---------------Infos du cercle c1
 - rayon      :   5,70
 - périmètre  :  35,81
 - surface    : 102,07

Infos du deuxième cercle
 - rayon      :   1,30
 - périmètre  :   8,17
 - surface    :   5,31

Infos du cercle c3
 - rayon      :   6,10
 - périmètre  :  38,33
 - surface    : 116,90


Process completed.

*/

Explications :

private double rayon ;

rayon est le seul champ d’information de la classe Cercle.

L’accès est privé : dans la classe Cercle, on a le droit d’accéder au champ rayon. En dehors de la classe Cercle, on n’a pas le droit d’accéder au champ rayon.

Très souvent, surtout pour IFT 1810, l’accès à un champ d’information est privé.

Constructeur

C’est une méthode de la classe permettant de construire (instancier, fabriquer) un objet de la classe. Cette méthode porte le même nom de la classe. Son but est de déterminer les champs d’informations.

Une classe peut avoir, aucune, une ou quelques constructeurs.

L’instruction : Cercle c1 = new Cercle(5.7) ; permet d’appeler le constructeur à 1 seul paramètre afin d’instancier l’objet c1 de la classe Cercle ayant le rayon 5.7.

L’instruction : c2 = new Cercle(); // par défaut 1.3 permet d’appeler le constructeur à aucun paramètre afin d’instancier l’objet c2 de la classe Cercle ayant le rayon 1.3 par défaut.

Les méthodes perimetre, surface et afficher sont des méthodes permettant d’appliquer sur un objet de la classe Cercle.

Dans main, on peut afficher le périmètre du cercle c1 :

System.out.printf("Le périmètre du cercle c1 : %.2f\n", c1.perimetre());

L’accès c1.perimetre() fonctionne car la méthode perimetre() est publique. C’est la même chose pour la méthode publique surface :

System.out.printf("La surface du cercle c2 : %.2f\n", c2.surface());

On expliquera en détails en classe.

Par contre, l’affichage suivante dans main :

System.out.printf("Le rayon du cercle c1 : %.2f\n", c1.rayon);

est invalide car le champ rayon est privé : on n’a pas le droit d’accéder à ce champ en dehors de la classe Cercle.

Méthode d’accès :

Pour afficher, par exemple, le rayon du cercle c1, on peut écrire d’abord la méthode d’accès dans la classe Cercle :

public double getRayon()
{
    return rayon;
} 

Dans main, par exemple, on peut afficher le rayon du cercle c1 comme suit :

System.out.printf("Le rayon du cercle c1 : %.2f\n", c1.getRayon());

Soit la classe Etudiant avec le champ codepermanent . . . :

class Etudiant  
 {  private codePerm; // exemple "LAFL12549007" 
                      // née le 12 avril 1990
      
     etc . . .

     public char getSexe()
      {
          if ( codeperm.charAt(6) >= 5)
                Return F;
          else  return M;
      } 
     etc . . .   
 }

Dans ce cas-ci, on accède à une partie du champ codePerm : le sexe de l’étudiant.

Méthode de modification :

Pour doubler le rayon du cercle c2, l’instruction suivante dans main : c2.rayon *= 2; est invalide car le champ rayon est privé.

Dans un tel cas, il suffit d’ajouter la méthode de modification suivante à la classe Cercle :

public void setRayon( double nouvRayon )
{
    Rayon = nouveauRayon;
}

Ainsi, pour double le rayon du cercle c2, ont peut écrire dans main :

c2.setRayon ( 2 * c2.getRayon() );

Pour ajouter 1.2 au rayon du cercle c1 :

c1.setRayon(c1.getRayon() + 1.2);

Exemple 2 : Attention au saut de ligne en Word

/* Fichier Ex2_Cercle.java
 * class Cercle avec constructeurs et quelques méthodes
 * Exemple d'un tableau des cercles, méthodes
 * d'accès et de modification. Le tri du tableau
 * des cercles.
 *
 *
 */
class Cercle
{
	// champ privé : rayon
	private double rayon;

	// un constructeur
	public Cercle(double r)
	{
		rayon = r;
	}

    // un autre constructeur
	public Cercle()
	{
		rayon = 12.345; // par  défaut
	}

    // calcul du périmètre d'un cercle
	public double perimetre()
	{
		return 2 * Math.PI * rayon;
	}

    // calcul de la surface d'un cercle
	public double surface()
	{
		return Math.PI * rayon * rayon;
	}

    // afficher les informations d'un cercle
	public void afficher(String message)
	{
		System.out.printf("%s : %7.1f %10.2f %8.2f\n",
		             message, rayon, perimetre(), surface());
	}

	// méthode d'accès
	public double getRayon()
	{
		return rayon;
	}

	// méthode de modification
	public void setRayon(double nouvRayon)
	{
		rayon = nouvRayon;
	}
}

public class Ex2_Cercle {

    // afficher le contenu du tableau des cercles
    static void afficher(Cercle[] cer, int nbCercles, String message)
    {
    	System.out.printf("\n\nContenu du tableau de %d cercles %s :\n", 
                              nbCercles, message);
    	System.out.printf(" Rayon  Périmètre    Surface\n");
    	for ( int i = 0 ; i < nbCercles; i++)
    	  System.out.printf("%6.2f %8.2f %10.2f\n", cer[i].getRayon(),   
            cer[i].perimetre(),cer[i].surface());
        System.out.printf("\n\n");
    }

    // une manière de trier un tableau des cercles
    // (tri par sélection vu avant l'intra)
    static void trier(Cercle[] cer, int nbCercles)
    {
    	for (int i = 0; i < nbCercles-1; i++)
    	{ int indMin = i;
    	  for (int j = i+1; j < nbCercles; j++)
    	  	 if ( cer[j].getRayon() < cer[indMin].getRayon() )
    	  	 	           indMin = j;
    	  if (indMin != i)
    	  {
    	  	  double tempo = cer[i].getRayon();
    	  	  cer[i].setRayon ( cer[indMin].getRayon());
    	  	  cer[indMin].setRayon(tempo);
    	  }
    	}
    }

    // déterminer puis afficher le cercle ayant le rayon le plus grand
    static void chercherPlusGrandRayon(Cercle[] cer, int nbCercles)
    {
    	int indMax = 0 ;
    	for(int i = 1 ; i < nbCercles; i++)
    		if ( cer[i].getRayon() > cer[indMax].getRayon())
    			   indMax = i;
        cer[indMax].afficher("Cercle ayant le rayon le plus grand");

    }

    public static void main(String[] args) {

        // instancier 3 cercles
    	Cercle c1 = new Cercle(5.3),
    	       c2 = new Cercle(1.7), c3 = new Cercle();

    	c3.afficher("Infos du cercle c3");

        System.out.printf("Le perimetre du cercle c2 : %.2f\n\n",
                              c2.perimetre());

        System.out.printf("La surface du cercle c1 : %.2f\n\n",
                              c1.surface());

       // exemple d'un petit tableau des cercles :
        Cercle[] cer = { new Cercle(5.3), new Cercle(4.7),
                          new Cercle(), new Cercle(10.4),
                          new Cercle(5.2) } ;
        int nbCercles = cer.length;

        cer[1].afficher("Infos de cer[1] ");
        // doubler le rayon du 2ième cercle
        cer[1].setRayon( 2 * cer[1].getRayon());
        cer[1].afficher("Infos de cer[1] après avoir doublé son rayon 
                                 ");

        // forme 2 : Classe.méthode "static"
        Ex2_Cercle.afficher(cer, nbCercles, "avant le tri") ; 
        // Ex2_Cercle. est optionnel

        // quel est le cercle ayant le plus grand rayon
        chercherPlusGrandRayon(cer, nbCercles);

        trier(cer, nbCercles);

        afficher(cer, nbCercles, "apres le tri selon les rayons") ;



    }
}
/* Compilation et Exécution:
--------------------Configuration: <Default>--------------------
Infos du cercle c3 :    12,3      77,57   478,78
Le perimetre du cercle c2 : 10,68

La surface du cercle c1 : 88,25

Infos de cer[1]  :     4,7      29,53    69,40
Infos de cer[1] après avoir doublé son rayon  :     9,4      59,06   277,59


Contenu du tableau de 5 cercles avant le tri :
 Rayon  Périmètre    Surface
  5,30    33,30      88,25
  9,40    59,06     277,59
 12,35    77,57     478,78
 10,40    65,35     339,79
  5,20    32,67      84,95


Cercle ayant le rayon le plus grand :    12,3      77,57   478,78


Contenu du tableau de 5 cercles apres le tri selon les rayons :
 Rayon  Périmètre    Surface
  5,20    32,67      84,95
  5,30    33,30      88,25
  9,40    59,06     277,59
 10,40    65,35     339,79
 12,35    77,57     478,78



Process completed.


*/

Trois formes d’accès en Java :

  1. forme 1 (très fréquence) :

objet.méthode (……..)

Appliquer une méthode sur l’objet

Exemples :

  • "Bonsoir".length() retourne 7 (longueur de la chaîne)

  • "Bonsoir".charAt(0) retourne ‘B’ (le caractère à l’indice 0 est la lettre ‘B’)

  • "Bonsoir".indexOf(‘n’) retourne 2 (on trouve la lettre ‘n’ à l’indice 2

  • "Bonsoir".substring(1, 3) retourne “on” (la sous-chaîne délimitée entre l’indice 1 inclus et l’indice 3 exclu)

  1. forme 2 (assez fréquence) :

classe.méthode static(……..)

Utiliser une méthode static d’une classe

Exemples :

Integer.parseInt("17") retourne 17 (valeur entière)

Math.sqrt(16.0) retourne la racine carrée de 16.0 qui vaut 4.0

  1. forme 3 (peu fréquence) :

classe.champ static Accès à un champ (attribut) static d’une classe

Exemples :

Math.PI vaut 3.14159… (valeur PI de la classe Math)

Integer.MAX_VALUE retourne 231-1 (l’entier le plus grand)

Class Math (pour applications mathématiques)

PI Math.PI vaut 3.14159…

public static final double PI

The double value that is closer than any other to pi, the ratio of the circumference of a circle to its diameter.

sqrt square root (racine carrée de …)

public static double sqrt(double a)

Math.sqrt(16.0) = 4.0

pow power puissance

public static double pow(double a, double b)

Math.pow(rayon,2) c’est rayon au carré

etc …

Class Integer

public static final int MIN_VALUE

Integer.MIN_VALUE : l’entier le plus petit

public static final int MAX_VALUE

Integer.MAX_VALUE : l’entier le plus grand

public static int parseInt(String s)

Integer.parseInt(“1234”) vaut 1234

Class Double

public static final double MIN_VALUE

Double.MIN_VALUE : epsilon

public static final double MAX_VALUE

Double.MAX_VALUE : le réel le plus grand