Looking for Computer Science  & Information Technology online courses ?
Check my new web site: https://www.yesik.it !

En programmation orientée objets, un objet est une unité qui regroupe à la fois des données et les traitements associés. Pendant l'exécution du programme, l'ensemble des objets évolue (certains sont créés, d'autres détruits) et la tâche à réaliser par le programme est effectuée en faisant interagir ces objets entre-eux.

Un objet peut représenter une notion concrète du domaine d'application du programme. Dans ce cas, on parle d'objet métier. A l'inverse, un objet peut aussi représenter une abstraction informatique. Dans ce cas, on parle d'objet système. A titre d'exemple, en Java, System.in et System.out sont des objets systèmes qui représentent respectivement l'entrée standard et la sortie standard.

Pas à pas (PHP)

Afin d'illustrer la notion d'objet, nous allons écrire un programme d'inventaire. Celui-ci gère un ensemble d'articles, permet d'en ajouter ou d'en enlever du stock, et finalement d'afficher l'état de celui-ci. Le langage retenu pour ce programme est PHP.

Données

Les données représentent ce qui va être manipulé par le programme. Dans le vocabulaire de la programmation orientée objets, pour parler des données propres à chaque objet, on parle de variables d'instances ou de données membres.

Dans notre cas, les données spécifiques à un article sont sa désignation, sa référence et la quantité en stock.

En pseudo-code, on pourrait commencer par décrire un Article ainsi:

Chaque Article
    possède une désignation
    possède une référence
    possède une quantité en stock

Note:

Ne faites pas la confusion: cette description ne décrit pas un article en particulier, mais ce qui est commun à tous les articles!

Et le code PHP équivalent serait (dans un fichier Article.php):

<?php
 
class Article {
	private	$designation;
	private $reference;
	private $quantiteEnStock;
}
 
?>

Initialisation

L'initialisation consiste à donner des valeurs de départ aux données d'un objet. Un objet est initialisé lors de sa création.

Maintenant que nous savons ce qu'il y a dans un article, nous allons déterminer comment on en crée un. Créer un article (ou pour utiliser le vocabulaire de la programmation orientée objets: construire un article), c'est déterminer quelles seront ses caractéristiques "de départ". Ce rôle est dévolu à un sous-programme appelé constructeur

Parfois, le constructeur peut déterminer ces valeurs initiales. Parfois, il ne peut pas. Quand un constructeur ne peut pas déterminer la valeur initiale d'une donnée d'un objet, il doit la recevoir en argument.

Commençons par la quantité en stock. Au début de l'application, la quantité en stock de chaque article est initalisée à 0 (zéro):

Chaque Article
    possède une désignation
    possède une référence
    possède une quantité en stock

    créer un Article fait:
        sa quantité en stock ← 0

L'équivalent PHP est le code suivant:

<?php
 
class Article {
	private	$designation;
	private $reference;
	private $quantiteEnStock;
 
	public function __construct() {
		$this->quantiteEnStock = 0; 
	}
}
 
?>

Point de syntaxe: Mot-clé __construct (PHP)

En PHP5, __construct (avec 2 soulignés) est le nom de la "fonction" qui sert de constructeur.

Maintenant la désignation et la référence. Contrairement à la quantité en stock, le constructeur ne peut pas savoir tout seul comment initialiser ces deux données membres. Il a donc besoin qu'on lui fournisse les données nécessaires. Le moyen naturel pour un constructeur de recevoir des données est de les recevoir en paramètres:

Chaque Article
    possède une désignation
    possède une référence
    possède une quantité en stock

    créer un Article à partir d'une designation et d'une référence fait:
        sa désignation ← la désignation reçue en argument
        sa référence ← la référence reçue en argument
        sa quantité en stock ← 0
<?php
 
class Article {
	private	$designation;
	private $reference;
	private $quantiteEnStock;
 
	public function __construct($designation, $reference) {
		$this->designation = $designation;
		$this->reference = $reference;
		$this->quantiteEnStock = 0; 
	}
}
 
?>

Point de syntaxe: Mot-clé this (PHP)

En PHP, le mot-clé this sert à désigner le receveur. C'est à dire l'objet courant (celui sur lequel on est en train de travailler).

Ainsi dans un constructeur, $this->designation signifie "la désignation de l'objet qu'on est en train de construire".

Traitement

Les traitements associés représentent ce que sait faire cet objet. Dans le vocabulaire de la programmation orientée objets, pour faire référence aux traitements associés à un objet, on parle de méthode ou de fonction membre.

Dans notre exemple, les traitements associés à un article sont au nombre de trois:


En pseudo-code, la déclaration complète de notre article serait:

Chaque Article
    possède une désignation
    possède une référence
    possède une quantité en stock

    créer un Article à partir d'une designation et d'une référence fait:
        sa désignation ← la désignation reçue en argument
        sa référence ← la référence reçue en argument
        sa quantité en stock ← 0

    sait que incrémenter le stock fait:
        sa quantité en stock ← sa quantité en stock + 1

    sait que décrémenter le stock fait:
        sa quantité en stock ← sa quantité en stock - 1

    sait que afficher fait:
        afficher "sa désignation (sa reférence): sa quantité en stock"

Et voici maintenant l'équivalent PHP complet:

<?php
 
class Article {
	private	$designation;
	private $reference;
	private $quantiteEnStock;
 
	public function __construct($designation, $reference) {
		$this->designation = $designation;
		$this->reference = $reference;
		$this->quantiteEnStock = 0; 
	}
 
	public function incrementerLeStock() {
		$this->quantiteEnStock = $this->quantiteEnStock + 1;
	}
 
	public function decrementerLeStock() {
		$this->quantiteEnStock = $this->quantiteEnStock - 1;
	}
 
	public function afficher() {
		print $this->designation . 
				"(" . $this->reference . "):" . 
				$this->quantiteEnStock . "\n";
	}
}
 
?>

Point de syntaxe: Retour à la ligne (PHP)

En PHP (comme dans d'autres langages, par exemple C++ et Java) ce qui délimite la fin d'une instruction est le point-virgule (;). Pas les retours à la ligne.

Ainsi, le code suivant:

return $this->designation . 
					"(" . $this->reference . "):" . 
					$this->quantiteEnStock;

est parfaitement identique au code suivant:

return $this->designation . "(" . $this->reference . "):" . $this->quantiteEnStock;

Point de syntaxe: Concatenation (PHP)

Le point (.) sert en PHP pour accoler deux morceaux de texte ensemble. C'est ce qu'on appelle une concaténation.

Par exemple, toutes les lignes suivantes affichent exactement la même chose:

print "Bonjour concaténation!";
print "Bonjour " . "concaténation!";
print "Bonjour" . " " . "concaténation!";

La concaténation est surtout utile lorsqu'il est nécessaire de construire une chaîne de caractère en mélangeant éléments "codés en dur", et contenu de variables ou de données membres:

$this->designation . "(" . $this->reference . "):" . $this->quantiteEnStock;

Programme principal

Maintenant, nous avons décrit un article en général. Nous connaissons donc:

Mais tout ceci n'est que de la description. Pour l'instant, nous n'avons pas créé d'article. Or pour pouvoir en manipuler un, il va nous falloir le créer. Autrement dit encore, notre programme ne fait rien pour l'instant: il lui manque le chef d'orchestre qui dit ce qui se passe quand on "lance" le programme. Ce chef d'orchestre, c'est le programme principal.

Pour cette introduction, notre programme principal va rester très simple. Il servira surtout à montrer comment on se sert d'un objet. Donc, les opérations que nous souhaiterions faire faire par notre programme sont les suivantes:

  1. tout d'abord le programme crée un certain nombre d'articles ("ballon de plage", "pelle en plastique" et "parasol");
  2. puis augmente la quantité en stock de certains d'entre-eux (15 ballons et 8 parasols),
  3. et enfin affiche l'inventaire

En pseudo-code:

le programme principal fait:
    définit ballon ← créer un nouvel Article à partir de désignation: "Ballon de plage" référence: BA101 
    définit pelle ← créer un nouvel Article à partir de désignation: "Pelle en plastique" référence: PE201 
    définit parasol ← créer un nouvel Article à partir de désignation: "Parasol: PA302

    répéter 15 fois
        demander à ballon de incrémenter le stock
    répéter 8 fois
        demander à parasol de augmenter le stock de 8

    demander à ballon de s'afficher
    demander à pelle de s'afficher
    demander à parasol de s'afficher

Notre programme principal s'écrirait en PHP (fichier main.php):

<?php
 
require_once("Article.php");
 
$ballon = new Article("Ballon de plage", "BA101");
$pelle = new Article("Pelle en plastique", "PE201");
$parasol = new Article("Parasol", "PA302");
 
for($i = 0; $i < 15; $i=$i+1)
    $ballon->incrementerLeStock();
 
for($i = 0; $i < 8; $i=$i+1)
    $parasol->incrementerLeStock();
 
 
header("Content-type: text/plain");
$ballon->afficher();
$pelle->afficher();
$parasol->afficher();
 
?>

Point de syntaxe: require_once

Le programme principal utilise la classe Article. Or celle-ci est déclarée dans le fichier Article.php. Pour que PHP connaisse cette classe pendant l'exécution du programme principal, il faut lui dire de lire cet autre fichier. C'est le rôle de l'instruction require_once:

require_once("Article.php");

Exécution

Pour tester ce programme, il vous faut copier les deux fichiers Article.php et main.php dans le répertoire de votre serveur web.

Si comme-moi vous utilisez une distribution Debian/Linux, il s'agit du répertoire /var/www:

sh$ cp Article.php /var/www
sh$ cp main.php /var/www

Enfin, pour charger ce programme principal dans votre navigateur, vous devrez vous connecter à votre serveur web local, et demander le chargement du programme principal. Pour faire tout cela, il suffit de pointer votre navigateur web préféré sur http://localhost/main.php. Vous devriez obtenir le résultat suivant:

Ballon de plage(BA101):15
Pelle en plastique(PE201):0
Parasol(PA302):8

Pendant l'exécution, trois objets de la classe Article ont existé simultanément en mémoire. Chacun d'eux avec sa référence, sa désignation et sa quantité en stock. Remarquez aussi sur le schéma ci-dessus que les objets sont distincts des variables: Ces dernières ne sont que des noms qui référencent les objets.

Java

Maintenant que nous avons détaillé ce programme en PHP, nous allons écrire le même, mais en Java.

Il y a deux différences notables entre la version Java et la version PHP. Tout d'abord, la syntaxe des langages est différente. Sur ce point, il n'y a pas grand chose à dire: la syntaxe est ce qu'elle est. Et il n'y a pas d'explication métaphysique au fait qu'en PHP une méthode est définie avec le nom clé function ou qu'en Java, on utilise la notation this. plutôt que this-> pour référencer une donnée membre. C'est comme ça, et il faut le savoir.

La seconde différence est à la fois moins visible et plus importante. Java est un langage statiquement typé. Alors que PHP est dynamiquement typé. Cela veut dire que quand on déclare une variable en Java (que ce soit une variable locale ou une donnée membre), il faut systématiquement indiquer quel type de donnée elle va contenir (du texte, un entier, etc...). En PHP ça n'était pas nécessaire: l'interpréteur "voyait bien" ce que vous aviez mis dans une variable. Ce sont deux philosophies différentes, A nouveau, inutile de digresser longtemps: c'est comme ça, et il faut s'y faire.

Voici le code complet de la classe Article en Java (fichier Article.java):

public class Article {
    private String  designation;
    private String  reference;
    private int     quantiteEnStock;
 
    public Article(String designation, String reference) {
        this.designation = designation;
        this.reference = reference;
        this.quantiteEnStock = 0;
    }
 
    public void incrementerLeStock() {
        this.quantiteEnStock = this.quantiteEnStock + 1;
    }
 
    public void decrementerLeStock() {
        this.quantiteEnStock = this.quantiteEnStock - 1;
    }
 
    public void afficher() {
        System.out.println(this.designation +
                                "(" + this.reference + "):" +
                                this.quantiteEnStock);
    }
}

Et voici maintenant le programme principal (fichier Inventaire.java):

public class Inventaire {
    static public void main(String[] args) {
        Article ballon  = new Article("Ballon de plage", "BA101");
        Article pelle   = new Article("Pelle en plastique", "PE201");
        Article parasol = new Article("Parasol", "PA302");
 
        for(int i = 0; i < 15; i=i+1) {
            ballon.incrementerLeStock();
        }
 
        for(int i = 0; i < 8; i=i+1) {
            parasol.incrementerLeStock();
        }
 
        ballon.afficher();
        pelle.afficher();
        parasol.afficher();
    }
}

Déclaration des variables

Comme dit en introduction, la différence importante entre Java et PHP au niveau du langage est la nécessité d'indiquer en Java le type des données manipulées. C'est visible partout où l'on déclare une variable.

Ainsi, comparez la déclaration des données membres de la classe Article en PHP et en Java:

/* PHP */
class Article {
    private $designation;
    private $reference;
    private $quantiteEnStock;
    ...
/* Java */
public class Article {
    private String  designation;
    private String  reference;
    private int     quantiteEnStock;
    ...

Ce qu'il faut remarquer ici, ça n'est pas la différence de syntaxe qui veut que le nom des variables en PHP commence par un dollar ($), mais le fait qu'en Java les variables sont typées lors de leur déclaration. Ainsi:

La déclaration de type est obligatoire en Java partout ou vous déclarez une variable. C'est donc aussi le cas lorsque vous déclarez les paramètres du constructeur:

   /* PHP */
   public function __construct($designation, $reference) {
   /* Java */
   public Article(String designation, String reference) {

C'est aussi le cas pour les variables locales:

   /* PHP */
   $ballon = new Article("Ballon de plage", "BA101");
   $pelle = new Article("Pelle en plastique", "PE201");
   $parasol = new Article("Parasol", "PA302");
   /* Java */
   Article ballon  = new Article("Ballon de plage", "BA101");
   Article pelle   = new Article("Pelle en plastique", "PE201");
   Article parasol = new Article("Parasol", "PA302");

Remarquez sur ce dernier point que le type des variables ballon, pelle et parasol est le nom de la classe de ces objets: Article. Définir une classe, c'est en fait définir un nouveau type utilisable dans le programme.

Enfin n'oubliez pas non plus que même les variables de boucles doivent être déclarées avec leur type:

for(int i = 0; i < 15; i = i + 1) {
...

Constructeur

Petit point de syntaxe, mais à ne pas oublier: en Java le constructeur est identifié dans la classe car son nom est le même que le nom de la classe:

/* PHP */
class Article {
    public function __construct($designation, $reference) {
            $this->designation = $designation;
            $this->reference = $reference;
            $this->quantiteEnStock = 0;
    }
/* Java */
public class Article {
    /* ... */
    public Article(String designation, String reference) {
        this.designation = designation;
        this.reference = reference;
        this.quantiteEnStock = 0;
    }

this optionnel

Autre différence de syntaxe entre PHP et Java, en Java le mot-clé this est optionnel – et généralement omis – s'il n'y a pas de confusion possible avec une autre variable.

Ainsi, ici, this est obligatoire pour obtenir le résultat désiré:

public class Article {
    private String  designation;
    private String  reference;
    private int     quantiteEnStock;

    public Article(String designation, String reference) {
        this.designation = designation;
        /* ... */


En effet, sans le mot-clé this il serait impossible de distinguer la donnée membre designation du paramètre designation.

Par contre, dans le fragment de code suivant, on ne peut pas confondre les données membres avec autre chose:

public class Article {
    private String  designation;
    private String  reference;
    private int     quantiteEnStock;

    /* ... */

    public void afficher() {
        System.out.println(this.designation +
                                "(" + this.reference + "):" +
                                this.quantiteEnStock);
    }

En effet, dans ce code, il s'agit de la méthode afficher de la classe Article. Dans ce contexte, designation, reference et quantiteEnStock font forcément référence aux données membres. En effet, il n'y a aucune variable locale et aucun paramètre de même nom déclaré dans cette méthode avec lesquelles une confusion serait possible. Par conséquent, il est possible en Java de se dispenser du mot-clé this tout en obtenant le résultat souhaité:

public class Article {
    private String  designation;
    private String  reference;
    private int     quantiteEnStock;

    /* ... */

    public void afficher() {
        System.out.println(designation +
                                "(" + reference + "):" +
                                quantiteEnStock);
    }

Groovy

Après l'étude des versions PHP et Java de ce programme, la comparaison avec d'autres langages devrait être facile. Commençons par Groovy. Groovy est un langage pour la plate-forme Java, avec une syntaxe proche de celle du langage Java, mais qui supporte un modèle de programmation dynamique. Ceci a notamment pour conséquence que, tout comme en PHP, il n'est pas nécessaire de déclarer le type de variables. On peut le faire, mais ça n'est pas obligatoire. Pour déclarer une variable sans préciser son type, on utilise le mot-clé def (qui lui aussi est optionnel, d'ailleurs...).

Voici le code du fichier Article.groovy qui définit la classe Article:

public class Article {
    def  designation;
    def  reference;
    def  quantiteEnStock;
 
    public Article(designation, reference) {
        this.designation = designation;
        this.reference = reference;
        this.quantiteEnStock = 0;
    }
 
    public incrementerLeStock() {
        quantiteEnStock = quantiteEnStock + 1;
    }
 
    public decrementerLeStock() {
        quantiteEnStock = quantiteEnStock - 1;
    }
 
    public afficher() {
        println "${designation} (${reference}): ${quantiteEnStock}";
    }
}

Point de syntaxe: (Groovy)

Avec Groovy, il est possible d'inclure le contenu de variables dans une chaîne de caractère:

       println "${designation} (${reference}): ${quantiteEnStock}";

Cette notation permet d'éviter les concaténations – souvent moins lisibles – de la forme:

       println designation + " (" + reference + "): " +  quantiteEnStock
Cette possibilité est présente aussi en PHP, bien que l'utilisation obligatoire du mot-clé this ne la rende pas aussi compacte que son homologue Groovy quand il s'agit d'inclure des données membres...

Et le programme principal dans le fichier Inventaire.groovy:

public class Inventaire {
    static main(args) {
        def ballon      = new Article("Ballon de plage", "BA101");
        def pelle       = new Article("Pelle en plastique", "PE201");
        def parasol     = new Article("Parasol", "PA302");
 
        15.times() {
            ballon.incrementerLeStock();
        }
 
        8.times() {
            parasol.incrementerLeStock();
        }
 
        ballon.afficher();
        pelle.afficher();
        parasol.afficher();
    }
}

C++

Si Groovy prend délibérément l'approche dynamique, C++ lui est un langage à typage statique. Tout comme Java. D'où déclaration obligatoire des types. Par contre, contrairement à tous les autres langages vus ici, C++ sépare clairement la déclaration d'une classe du code à proprement parler des méthodes.

.h et .cc

Traditionnellement le "code" se trouve dans des fichiers avec l'extension .cc et les déclarations de classe dans des fichiers avec l'extension .h (ou parfois même sans extension du tout).

Par conséquent, notre classe Article sera déclarée dans le fichier Article.h et le code de ses méthodes defini dans Article.cc. Voici le contenu de Article.h:

#include <string>
 
class Article
{
    private:
    std::string     _designation;
    std::string     _reference;
    int             _quantiteEnStock;
 
    public:
    Article(std::string designation, std::string reference);
 
    void incrementerLeStock();
    void decrementerLeStock();
    void afficher() const;
};

Remarque:

Le souligné (_) pour commencer le nom des données membres n'est pas obligatoire. Néanmoins, c'est souvent l'usage en C++ d'utiliser une convention pour bien différencier les données membres des variables locales ou autres. Vous rencontrerez diverses conventions. Pour ma part, j'utilise un souligné...

Point de syntaxe: Le mot-clé const (C++)

Le mot-clé const après la déclaration de la méthode afficher indique que cette méthode ne modifiera pas l'objet. Ce mot-clé est optionnel, mais si on le met, le compilateur peut vérifier que l'on respecte bien notre engagement, et que l'affichage de va pas modifier l'article affiché.

Le .h déclare la classe Article. On y trouve entre autre les diverses méthodes auxquelles chaque article peut répondre. Il nous manque la mise en oeuvre de ces méthodes (et du constructeur). C'est ce que nous allons trouver dans le fichier Article.cc:

#include <iostream>
 
#include "Article.h"
 
Article::Article(std::string designation, std::string reference)
        :   _designation(designation),
            _reference(reference),
            _quantiteEnStock()
{
}
 
void Article::incrementerLeStock() {
    _quantiteEnStock = _quantiteEnStock + 1;
}
 
void Article::decrementerLeStock() {
    _quantiteEnStock = _quantiteEnStock - 1;
}
 
void Article::afficher() const {
    std::cout << _designation <<
                 "(" << _reference << "):" <<
                 _quantiteEnStock << std::endl;
}

Point de syntaxe: include (C++)

Pour compiler un fichier, le compilateur C++ doit connaître tous les types de données utilisés. Par exemple, pour compiler les méthodes de la classe Article, le compilateur doit savoir que cette classe existe. D'où le #include "Article.h". De la même manière, la déclaration de la classe Article utilise le type std::string qui est déclaré dans le fichier string. D'où le #include <string>. Enfin, std::cout qui sert pour l'affichage est déclaré dans iostream. D'où le #include <iostream>. Simple, non?

Dernière subtilité, pour inclure les fichiers systèmes (ou les fichiers standards) on utilise la notation #include <...>. Pour inclure les fichiers propre au programme, on utilise la notation #include "...":

#include <iostream>

#include "Article.h"

Programme principal

Enfin, il nous manque le programme principal. Celui-ci n'a pas besoin d'être déclaré. Pas besoin d'un main.h. Le fichier de définition main.cc suffit:

#include "Article.h"
 
int main()
{
    Article *ballon     = new Article("Ballon de plage", "BA101");
    Article *pelle      = new Article("Pelle en plastique", "PE201");
    Article *parasol    = new Article("Parasol", "PA302");
 
    for(int i = 0; i < 15; i=i+1) {
        ballon->incrementerLeStock();
    }
 
    for(int i = 0; i < 8; i=i+1) {
        parasol->incrementerLeStock();
    }
 
    ballon->afficher();
    pelle->afficher();
    parasol->afficher();
 
    delete parasol;
    delete pelle;
    delete ballon;
 
    return 0;
}

Point de syntaxe: new et delete (C++)

Tous les autres langages que nous utilisons dans cet article utilisent un "ramasse miette" (garbage collector). C'est à dire que les objets sont créés dans le tas et supprimés automatiquement quand ils ne sont plus utilisés.

C++ est différent. Les objets crées dans le tas par l'opérateur new y restent tant que le programmeur ne les supprime pas avec l 'opérateur delete:

   Article *ballon     = new Article("Ballon de plage", "BA101");
   Article *pelle      = new Article("Pelle en plastique", "PE201");
   Article *parasol    = new Article("Parasol", "PA302");

   /* ... */

   delete parasol;
   delete pelle;
   delete ballon;

C++ est aussi différent parce qu'il permet également de créer des objets sur la pile. Dans ce cas, les objets sont automatiquement détruits à la fin du bloc de code entre accolades où l'objet est déclaré:

int main()
{
    Article ballon("Ballon de plage", "BA101");
    Article pelle("Pelle en plastique", "PE201");
    Article parasol("Parasol", "PA302");
 
    for(int i = 0; i < 15; i=i+1) {
        ballon.incrementerLeStock();
    }
 
    for(int i = 0; i < 8; i=i+1) {
        parasol.incrementerLeStock();
    }
 
    ballon.afficher();
    pelle.afficher();
    parasol.afficher();
 
    return 0;
} // les objets sur la pile ballon, pelle et parasol sont détruits ici

Exécuter le programme

Pour compiler et exécuter le programme, vérifiez tout d'abord que vous avez bien les trois fichiers Article.h, Article.cc et main.cc dans votre répertoire courant:

sh$ ls -l
total 12
-rw-r--r-- 1 sylvain sylvain 520 2009-01-05 17:20 Article.cc
-rw-r--r-- 1 sylvain sylvain 313 2009-01-05 17:20 Article.h
-rw-r--r-- 1 sylvain sylvain 475 2009-01-05 17:48 main.cc

Ok, maintenant, la compilation. Nous allons compiler simultanément les deux fichiers .cc

Ne compilez pas les .h!

Les fichiers .h ne se compilent pas directement! Par contre, ils sont utilisés lors de la compilation des fichiers .cc via les directives include qu'ils contiennent.

sh$ g++ -Wall -Werror Article.cc main.cc -o inventaire

Si vous n'avez pas fait de faute de frappe, la compilation doit se passez sans problème, et vous devriez obtenir un programme exécutable inventaire:

sh$ ls -l
total 24
-rw-r--r-- 1 sylvain sylvain   520 2009-01-05 17:20 Article.cc
-rw-r--r-- 1 sylvain sylvain   313 2009-01-05 17:20 Article.h
-rwxr-xr-x 1 sylvain sylvain 12010 2009-01-05 17:55 inventaire
-rw-r--r-- 1 sylvain sylvain   475 2009-01-05 17:48 main.cc

Il ne reste qu'a essayer le programme:

sh$ ./inventaire
Ballon de plage(BA101):15
Pelle en plastique(PE201):0
Parasol(PA302):8

JavaScript

Dans les langages présentés ici, C++ est certainement celui qui est le plus difficile à maîtriser. Quand à JavaScript, sous une apparente simplicité, il se révèle un langage puissant, mais aussi avec la syntaxe la plus exotique.

En effet, contrairement aux autres langages présentés ici, JavaScript n'a pas la notion de classe. JavaScript repose sur des fonctions (qui sont en réalité des fermetures – mais c'est une autre histoire). Et les objets sont directement crées par la fonction qui sert de constructeur.

Une fois n'est pas coutume, nous allons mettre tout le code dans un seul fichier Inventaire.js:

var Article = function(designation, reference) {
    var that = {}; /* création d'un objet "vide" */
 
    var quantiteEnStock = 0;
 
    that.incrementerLeStock = function() {
        quantiteEnStock = quantiteEnStock + 1;
    }
 
    that.decrementerLeStock = function() {
        quantiteEnStock = quantiteEnStock - 1;
    }
 
    that.afficher = function() {
        document.write(designation +
                       "(" + reference + "): " +
                       quantiteEnStock + "<br/>");
    }
 
    return that;
};
 
var ballon = Article("Ballon de plage", "BA101");
var pelle = Article("Pelle en plastique", "PE201");
var parasol = Article("Parasol", "PA302");
 
for(i = 0; i < 15; i = i + 1)
    ballon.incrementerLeStock();
 
for(i = 0; i < 8; i = i + 1)
    parasol.incrementerLeStock();
 
ballon.afficher();
pelle.afficher();
parasol.afficher();

Le programme principal (la partie "du bas") ne pose pas de problème. Mais revenons plutôt sur le constructeur. En JavaScript, le constructeur est vraiment une fonction qui construit un objet. Ainsi, on part d'un objet vide:

   var that = {}; /* création d'un objet "vide" */

Puis on lui ajoute ses méthodes:

   that.incrementerLeStock = function() {
       quantiteEnStock = quantiteEnStock + 1;
   }
   that.decrementerLeStock = function() {
       quantiteEnStock = quantiteEnStock - 1;
   }
   that.afficher = function() {
       document.write(designation +
                      "(" + reference + "): " +
                      quantiteEnStock + "<br/>");
   }

Si l'on admet qu'une fonction puisse être définie dans une autre fonction, ça ne pose pas de problème. Par contre, observez bien le code. Où sont les données membres?

D'accord, on voit bien quantiteEnStock:

   var quantiteEnStock = 0;

Mais la désignation et la référence? Ou sont-elles? Avant d'aller plus loin, nous allons tout de même vérifier que ce programme fonctionne. Pour ce faire, il nous faut un fichier html à charger dans votre navigateur:

<html>
<head><title>Inventaire</titre></head>
<body>
    <script lang="text/javascript" src="Inventaire.js"></script>
</body>
</html>

Reste à charger ce fichier dans votre navigateur préféré (moi, c'est iceweasel):

sh$ iceweasel Inventaire.html

Et voilà:

Visiblement, ça marche! En fait, et c'est une particularité des langages à fermeture, les variables locales restent accessibles aux fonctions internes même quand la fonction externe est terminée. Autrement dit, dans le code suivant:

var Article = function(designation, reference) {
    var that = {}; /* création d'un objet "vide" */
 
    var quantiteEnStock = 0;
 
    /* ... */
 
    that.afficher = function() {
        document.write(designation +
                       "(" + reference + "): " +
                       quantiteEnStock + "<br/>");
    }
 
    return that;
};

La fonction afficher pourra continuer d'accéder à la variable locale quantiteEnStock et aux paramètres designation et reference même quand le constructeur aura fini de s'exécuter. C'est une énorme différence avec d'autres langages où une variable locale cesse d'exister à la fin du bloc entre accolades où elle est déclarée.

En fait, c'est exactement ce qui distingue une fermeture (closure) d'une fonction: la possibilité d'accéder aux données locales d'une fonction d'ordre supérieur. De tous les langages utilisés ici, seuls JavaScript et Groovy supportent les fermetures. Leur support pour Java est envisagé – peut-être avec Java 7.

A vous de jouer

Dans le but de motiver ses employés, un directeur de restaurant envisage de mettre en place un logiciel permettant au client de donner un avis sur la qualité du service.

Le principe est simple: à l'issue du repas, les clients sont invités à émettre un avis sur le serveur qui s'est occupé d'eux. Cet avis peut être:

Régulièrement, les serveurs ayant plus d'avis positifs que négatifs ont droit à une prime.

Voici le programme principal contenu dans le fichier Vote.java:

import java.util.*;
 
public class Vote {
    static public void main(String[] args) {
        Employe     bob     = new Employe("Bob l'Eponge");
        Employe     carlo   = new Employe("Carlo Tentacule");
 
        /*
         * Lecture des votes
         */
        Scanner     sc      = new Scanner(System.in);
        boolean     fini    = false;
 
        while(!fini) {
            /* lit le prochain mot */
            String commande = sc.next();
 
            if ((commande == null) || (commande.equals("fin"))) {
                fini = true;
            }
            else if (commande.equals("+bob")) {
                bob.recoitUnVotePositif();
            }
            else if (commande.equals("-bob")) {
                bob.recoitUnVoteNegatif();
            }
            else if (commande.equals("+carlo")) {
                carlo.recoitUnVotePositif();
            }
            else if (commande.equals("-carlo")) {
                carlo.recoitUnVoteNegatif();
            }
            else
                System.err.println("Commande non reconnue: " + commande);
        }
 
        /*
         * Affichage du résultat
         */
        bob.faitSonAutocritique();
        carlo.faitSonAutocritique();
    }
}

Ce programme à l'air plus complexe que ce que nous avons vu. C'est simplement parce qu'il contient une boucle pour lire et décoder les commandes tapées par l'utilisateur au clavier.

En examinant un peu le code source, vous voyez également que les commandes sont au nombre de 5: fin, +bob, -bob, +carlo et -carlo. Evidemment la commande fin sert à indiquer la fin des votes, et les autres commandes servent à donner des votes positifs ou négatifs aux deux employés.

Le programme principal est complet. Par contre, il manque la définition de la classe Employé. Et c'est votre travail que d'écrire le fichier Employe.java.

Pour vous aider, en voici tout de même une bonne partie:

public class Employe {
    private String      nom;
    private int         votesPositifs;
    private int         votesNegatifs;
 
    public Employe(String nom) {
        /* A COMPLETER */
    }
 
    /* AJOUTER LA METHODE recoitUnVotePositif() */
 
    /* AJOUTER LA METHODE recoitUnVoteNegatif() */
 
    public void faitSonAutocritique() {
        if (votesPositifs > votesNegatifs)
            System.out.println(nom + " mérite une prime");
        else
            System.out.println(nom + " essaiera de faire mieux la prochaine fois");
    }
}