Résumé

Le manuel indispensable à tout étudiant en informatique (IUT, écoles spécialisées, écoles d'ingénieurs) sur la programmation orientée objet !

L’objet par la pratique avec Python, Java, C# et C++ et PHP 5… en UML 2

Cette sixième édition de l’ouvrage L’orienté objet décortique l’ensemble des mécanismes de la programmation objet (classes et objets, interactions entre classes, envois de messages, encapsulation, héritage, polymorphisme, interface, multithreading, sauvegarde des objets, programmation distribuée, modélisation…) en les illustrant d’exemples empruntant aux technologies les plus populaires : Java et C#, C++, Python, PHP 5, UML 2, LINQ mais aussi les services web, Corba, les bases de données objet, différentes manières de résoudre la mise en correspondance relationnel/objet dont le langage innovant de requête objet LinQ et enfin les design patterns. Chaque chapitre est introduit par un dialogue vivant, à la manière du maître et de l’élève, et se complète de nombreux exercices en UML 2, Java, Python, PHP 5, C# et C++.

À qui s’adresse ce livre ?

• Ce livre sera lu avec profit par tous les étudiants de disciplines informatiques liées à l’approche objet (programmation orientée objet, modélisation UML, Java, Python, PHP 5, C#/C++…) et pourra être utilisé par leurs enseignants comme matériel de cours.

• Il est également destiné à tous les développeurs qui souhaitent approfondir leur compréhension des concepts objet sous-jacents au langage qu’ils utilisent.

Au sommaire

Principes de base : quel objet pour l’informatique • Un objet sans classe… n’a pas de classe • Du faire-savoir au savoir-faire… du procédural à l’OO • Ici Londres : les objets parlent aux objets • Collaboration entre classes • Méthodes ou messages ? • L’encapsulation des attributs • Les classes et leur jardin secret • Vie et mort des objets • UML 2 • Héritage • Redéfinition des méthodes • Abstraite, cette classe est sans objet • Clonage, comparaison et assignation d’objets • Interfaces • Distribution gratuite d’objets : pour services rendus sur le réseau • Multithreading • Programmation événementielle • Persistance d’objets • Et si on faisait un petit flipper ? • Les graphes • Petite chimie et biologie OO amusante • Design patterns.

Le code source des exercices et leurs corrections sont fournis sur le site d’accompagnement www.editions-eyrolles.com.

Biographie auteur

Hugues Bersini

Membre de l’Académie Royale de Belgique, ingénieur physicien, directeur du Laboratoire d’intelligence artificielle de l’Université libre de Bruxelles, Hugues Bersini enseigne l’informatique et la programmation aux facultés polytechnique et Solvay de cette même université.

www.editions-eyrolles.com

Hugues Bersini

La programmation

orientée

objet

6e édition

ÉDITIONS EYROLLES

61, bd Saint-Germain

75240 Paris Cedex 05

www.editions-eyrolles.com

Cet ouvrage est la sixième édition du livre de Hugues Bersini et Ivan Wellesz, paru à l’origine sous le titre L’orienté objet, puis sous le titre La programmation orientée objet lors de la quatrième édition (G12441).

Remerciements à Anne Bougnoux pour sa relecture.

En application de la loi du 11 mars 1957, il est interdit de reproduire intégralement ou partiellement le présent ouvrage, sur quelque support que ce soit, sans autorisation de l’éditeur ou du Centre Français d’Exploitation du Droit de Copie, 20, rue des Grands-Augustins, 75006 Paris.

© Groupe Eyrolles, 2002, 2004, 2007, 2009, 2011 et 2013 pour la présente édition, ISBN : 978-2-212-13578-7

Dans la collection Noire

Dans la collection Blanche

Dans les collections Design web et A Book Apart

Autres ouvrages

Avant-propos

Aux tout débuts de l’informatique, le fonctionnement interne des processeurs décidait de la seule manière efficace de programmer un ordinateur. Alors que l’on acceptait tout programme comme une suite logique d’instructions, il était admis que l’organisation du programme et la nature même de ces instructions ne pouvaient s’éloigner de la façon dont le processeur les exécutait : pour l’essentiel, des modifications de données mémorisées, des déplacements de ces données d’un emplacement mémoire à un autre, des opérations d’arithmétique et de logique élémentaire, et de possibles ruptures de séquence ou branchements.

La mise au point d’algorithmes complexes, dépassant les simples opérations mathématiques et les simples opérations de stockage et de récupérations de données, obligea les informaticiens à effectuer un premier saut dans l’abstrait, en inventant un style de langage dit procédural, auquel appartiennent les langages Fortran, Cobol, Basic, Pascal, C… Les codes écrits dans ces langages sont devenus indépendants des instructions élémentaires propres à chaque type de processeur. Grâce à eux, les informaticiens ont pris quelques distances par rapport aux processeurs (en ne travaillant plus directement à partir des adresses mémoire et en évitant la manipulation directe des instructions élémentaires) et ont élaboré une écriture de programmes plus proche de la manière naturelle de poser et de résoudre les problèmes. Il est incontestablement plus simple d’écrire : c = a + b qu’une suite d’instructions telles que "load a, reg1", "load b, reg2", "add reg3, reg1, reg2", "move c, reg3", ayant pourtant la même finalité. Une opération de traduction automatique, dite de compilation, se charge de traduire le programme, écrit au départ avec ces nouveaux langages, dans les instructions élémentaires seules comprises par le processeur.

La montée en abstraction permise par ces langages de programmation présente un double avantage : une facilité d’écriture et de résolution algorithmique, ainsi qu’une indépendance accrue par rapport aux différents types de processeur existant aujourd’hui sur le marché. Le programmeur se trouve libéré des détails d’implémentation machine et peut se concentrer sur la logique du problème et ses voies de résolution.

Plus les problèmes à affronter gagnaient en complexité – comptabilité, jeux automatiques, compréhension et traduction des langues naturelles, aide à la décision, bureautique, conception et enseignement assistés, programmes graphiques, etc. –, plus l’architecture et le fonctionnement des processeurs semblaient contraignants. Il devenait vital d’inventer des mécanismes informatiques simples à mettre en œuvre pour réduire cette complexité et rapprocher encore plus l’écriture de programmes des manières humaines de poser et résoudre les problèmes.

Avec l’intelligence artificielle, l’informatique s’inspira de notre mode cognitif d’organisation des connaissances, comme un ensemble...

1

Principes de base : quel objet pour l’informatique ?

Ce chapitre présente les briques de base de la conception et de la programmation orientée objet (OO). Il s’agit pour l’essentiel des notions d’objet, de classe, de message et d’héritage. À ce stade, aucun approfondissement technique n’est effectué. Les quelques extraits de code seront écrits dans un pseudo langage très proche de Java. De simples petits exercices de pensée composent une mise en bouche, toute en intuition, des éléments essentiels de la pratique OO.

SOMMAIRE

Introduction à la notion d’objet

Introduction à la notion et au rôle du référent

L’objet dans sa version passive et active

Introduction à la notion de classe

Les interactions entre objets

Introduction aux notions d’héritage et de polymorphisme

DOCTUS — Tu as l’air bien remonté, aujourd’hui !

CANDIDUS — Je cherche un objet, mon vieux ! Je le cherche partout ! C’est ce sacré objet logiciel dont tout le monde parle, mais il est aussi insaisissable que le Yéti…

DOC. — Laisse-moi t’expliquer. Au commencement… il y avait l’ordinateur, tout juste né. C’est nous qui étions à son service pour le pouponner. Aujourd’hui, il comprend beaucoup mieux ce qu’on attend de lui. On peut lui parler en adulte, lui expliquer les choses d’une façon plus structurée…

CAND. — …Veux-tu dire qu’il comprend ce que nous voulons si nous le lui spécifions ?

DOC. — Doucement ! Je dis simplement que notre bébé est aujourd’hui capable de manipuler lui-même les informations qu’on lui confie. Il a ses propres méthodes d’utilisation et de rangement. Il ne veut même plus qu’on touche à ses jouets.

Jetons un rapide coup d’œil par la fenêtre ; nous apercevons… des voitures, des passants, des arbres, un immeuble, un avion… Cette simple perception est révélatrice d’un ensemble de mécanismes cognitifs des plus subtils, dont la compréhension est une porte d’entrée idéale dans le monde de l’informatique orientée objet. En effet, pourquoi n’avoir pas cité « l’air ambiant », la « température », la « bonne ambiance » ou encore « la lumière du jour », que l’on perçoit tout autant ? Pourquoi les premiers se détachent-ils de cette toile de fond parcourue par nos yeux ?

Tout d’abord, leur structure est singulière, compliquée ; ils présentent une forme alambiquée, des dimensions particulières, parfois une couleur uniforme et distincte du décor qui les entoure. Nous dirons que chacun se caractérise par un ensemble « d’attributs » structuraux, prenant pour chaque objet une valeur particulière : une des voitures est rouge et plutôt longue, ce passant est grand, assez vieux, courbé, etc. Ces attributs structuraux – et leur présence conjointe dans les objets – sont la raison première de l’attrait perceptif qu’ils exercent. C’est aussi la raison de la segmentation et de la nette séparation perceptive qui en résulte, car si les voitures et les arbres se détachent en effet de l’arrière plan, nous ne les confondons en rien.

Le trio <entité, attribut, valeur>

Nous avons l’habitude de décrire le monde qui nous entoure à l’aide de ce trio que les informaticiens se plaisent à nommer <entité (ou objet), attribut, valeur> ; par exemple <voiture, couleur, rouge>, <voiture, marque, peugeot>, <passant, taille, grande>, <passant, âge, 50>. Les objets (la voiture et le passant) vous sautent aux yeux parce que chacun se caractérise par un ensemble d’attributs (couleur, âge, taille), prenant une valeur particulière, uniforme « sur tout l’objet ».

La nature des attributs est telle qu’ils servent à définir un nombre important d’objets, pourtant très différents. La voiture a une taille comme le passant. L’arbre a une couleur comme la voiture. Le monde des attributs est beaucoup moins diversifié que celui des objets. C’est une des raisons qui nous permettent de regrouper les objets en classes et sous-classes, comme nous le découvrirons plus tard.

Que ce soit comme résultat de nos perceptions ou dans notre pratique langagière, les attributs et les objets jouent des rôles très différents. Les attributs structurent nos perceptions et ils servent, par exemple, sous forme d’adjectifs, à qualifier les noms qui les suivent ou les précèdent. La première conséquence de cette simple faculté de découpage cognitif sur l’informatique d’aujourd’hui est la suivante :

imagesObjets, attributs, valeurs

Il est possible dans tous les langages informatiques de stocker et de manipuler des objets en mémoire, comme autant d’ensembles de couples attribut/valeur.

Stockage des objets en mémoire

Dans la figure qui suit, nous voyons apparaître ces différents objets dans la mémoire de l’ordinateur. Chacun occupe un espace mémoire qui lui est propre et alloué lors de sa création. Pour se faciliter la vie, les informaticiens ont admis un ensemble de « types primitifs » d’attributs, dont ils connaissent à l’avance la taille requise pour encoder la valeur.

Figure 1–1
Les...

2

Un objet sans classe… n’a pas de classe

Ce chapitre a pour but de préciser la notion de classe : de quoi une classe est-elle faite et quel rôle jouet-elle durant le développement du programme, sa compilation, sa structuration finale, et surtout le découpage du programme qu’elle permet. On verra que les classes servent à la fois de modèle à respecter stricto sensu par les objets, ainsi que de modules idéaux pour l’organisation logicielle.

SOMMAIRE

Classe

Méthode

Signature de méthode

La classe, vigile de son bon usage

Méthodes et attributs statiques

La découpe logicielle en classes

CANDIDUS — Explique-moi le mode d’emploi de ton bébé.

DOCTUS — Bon ! Autrefois (mode procédural), il fallait chatouiller bébé au bon endroit pour le forcer à faire ce qu’on attendait de lui. Aujourd’hui (orienté objet), il faut lui fournir des moyens d’agir qui lui sont accessibles. Si nous nous arrangeons pour organiser son environnement comme un ensemble de modules simples et complets, il nous fera tout un tas de petits miracles.

CAND. — Et on sait bien que beaucoup de programmes marchent par miracle…

DOC. — …Ces modules ne sont pas autre chose qu’un ensemble de pièces avec leurs règles d’utilisation.

CAND. — J’imagine que tous ces petits modules sont en fait les différents composants d’une structure. Seule la vision globale de l’ensemble laissera voir la complexité du travail de bébé… Ça semble génial ! Tu viens de faire la même découverte que Descartes quand il voulait tout expliquer en réduisant tout ce qui lui apparaissait complexe en des parties plus simples !

DOC. — Sans aller jusque là, il s’agit simplement d’orienter l’effort à fournir. C’est toi qui devras tout expliquer quand tu réaliseras un programme particulier. Ce qu’il faut retenir, c’est que ton effort devra être basculé de la phase de développement vers la phase de conception. Tes données ne seront plus ces choses inertes avec lesquelles tu jonglais en te servant de fonctions bien trop complexes. Elles seront des acteurs à part entière de ton programme ; elles sauront quoi y faire et avec qui le faire.

Constitution d’une classe d’objets

Le premier chapitre a apporté une première justification à la nécessité de faire précéder toute manipulation d’objets d’une structure de données, associant aux attributs de l’objet les seules méthodes qui peuvent y avoir accès. Dorénavant, chaque objet créé le sera à partir d’une classe à laquelle il sera tenu de se conformer tout au long de son existence. Pourtant, dans la réalité, rien n’interdit à un objet de changer de statut ou de comportement ; par exemple, un étudiant peut devenir professeur ou un professeur d’informatique devenir sommelier. C’est possible dans la réalité, mais pas dans l’OO d’aujourd’hui : l’objet est coincé, figé par sa classe, même s’il s’y sent parfois à l’étroit. Dans les langages OO, la classe est le modèle à respecter stricto sensu, comme le plan de l’architecte pour une maison. La classe se décrit au moyen de trois informations : le nom de la classe (FeuDeSignalisation sur la figure 2.1), le nom des attributs (couleur, position et hauteur) et leur type (int pour les deux premiers et double pour le troisième), et enfin, le nom des méthodes (change, clignote) avec la liste des arguments et le type de ce que les méthodes retournent.

Figure 2–1
Un exemple d’une classe et des trois types d’information qui la composent

Programmation orientée objet, ou programmation orientée classe ?

En réalité, un programmeur OO passe bien plus de temps à faire ses classes qu’à se préoccuper de ce qu’il adviendra aux objets quand ces derniers s’exécuteront en effet. Plutôt que « programmation orientée objet », il aurait été plus adéquat de qualifier ce type de programmation d’« orientée classe » !

Les trois informations constitutives de la classe

Toute définition de classe inclut trois informations : d’abord, le nom de la classe, ensuite, ses attributs et leur type, enfin, ses méthodes.

Définition d’une méthode de la classe : avec ou sans retour

Une méthode retourne quelque chose si le corps de ses instructions se termine par une expression telle que return x. Si c’est le cas, son nom sera précédé du type de ce qu’elle retourne. Par exemple, la méthode change, modifiant la couleur du feu, pourrait se définir comme suit :

int change() {

couleur = couleur + 1 ;

if couleur == 4 couleur = 1;

return couleur ; /* la méthode retourne un entier */

}

imagesCommentaires

/* … */ encadre des commentaires à l’intérieur d’un code. Lorsque les commentaires restent sur une seule ligne, on peut également utiliser //. En Python, en revanche, tous les commentaires restent sur une seule ligne et doivent débuter par le dièse # plutôt que le //.Toute écriture mise en commentaire est désactivée dans le code. Nous utiliserons beaucoup les commentaires dans nos codes, de manière à expliquer ceux-ci sans pour autant modifier la façon dont ils s’exécutent.

Notre méthode retourne une « couleur », donc elle est de type entier. La rencontre du mot return met fin à l’exécution de la méthode et remplace celle-ci dans le code qui l’appelle par la valeur de ce retour. Il est bien entendu possible d’exécuter la méthode sans pour autant récupérer la valeur qu’elle retourne.

Certaines méthodes ne retournent rien ; elles sont alors précédées du mot-clé void au lieu d’un type. C’est le cas de la seconde méthode de la classe, clignote(). Son appel dans un corps d’instructions se fait indépendamment d’un contexte opératoire spécifique, alors que l’appel de change() peut être intégré à une expression (où il pourrait être remplacé par un simple entier), par exemple :

if (change() == 1) print ("le feu est vert")

ou encore :

int b = change() + 2 ;

imagesFonctions et procédures

Les praticiens des langages de programmation procéduraux retrouveront là la distinction faite généralement dans ces langages...

3

Du faire savoir au savoir-faire… du procédural à l’OO

Ce chapitre distingue l’approche dite procédurale, axée sur les grandes activités de l’application, de l’approche objet, axée sur les acteurs de la simulation et la manière dont ils interagissent. Nous illustrons cette distinction à l’aide de la simulation d’un petit écosystème.

SOMMAIRE

Procédural versus OO

Activité versus acteurs

Dépendance fonctionnelle mais indépendance dans le développement

Introduction à la relation entre classes ou client-fournisseur

Acteurs collaborant

CANDIDUS — Bon ! Maintenant qu’on a donné des jouets à bébé, il faut lui expliquer comment tout cela fonctionne. J’aurais envie de mettre tout à sa portée, bien rangé sur la table, mais ne va-t-il pas tout mélanger ?

DOCTUS — Mieux vaut lui présenter chacun des petits puzzles l’un après l’autre. Je propose de diviser une structure complexe en sous-ensembles simples. Par exemple, selon la méthode classique, nos voitures se présentaient sous forme de pièces détachées devant être assemblées et contrôlées et c’était à toi d’en vérifier l’intégrité avant chaque usage. Avec l’OO, ta voiture est toujours prête, tu montes dedans et c’est parti !

CAND. — Normalement, c’est le programmeur qui se charge de réaliser ce qui a été envisagé lors de la phase de conception…

DOC. — Oui, mais la programmation objet a un rôle à jouer autant à la phase d’analyse qu’à la conception, et même à l’exécution. Chaque pièce de nos puzzles sera indissociable de son mode d’emploi ! Il s’agit, pour schématiser, d’établir un jeu de transactions entre les différents acteurs. Et chaque programmeur – pardon, chaque fabricant de puzzle – aura toute une panoplie de moyens pour mettre en place les permissions ou interdictions qu’il jugera utiles. On est vraiment très proche d’une organisation naturelle.

L’orienté objet est loin d’être une pratique neuve en informatique, puisque le premier langage OO important, Simula, remonte à 1966.

Kristen Nygaard et Ole-Johan Dahl : Simula

Simula est l’ancêtre de tous les langages orientés objet ; un ancêtre vieux seulement d’un demi-siècle, car il a été proposé par deux...

4

Ici Londres : les objets parlent aux objets

Ce chapitre illustre et décrit le mécanisme d’envoi de messages qui est à la base de l’interaction entre les objets. Cette interaction exige que les classes dont sont issus ces objets entrent dans un rapport de composition, d’association ou de dépendance. Ces messages peuvent s’enclencher de manière récursive.

SOMMAIRE

Envoi de messages

Composition, association et dépendance entre classes

De la sévérité du compilateur

Réaction en chaîne d’envois de messages

CANDIDUS — Alors, il n’y en a plus que pour les objets… Les procédures passent à la trappe, c’est bien ça ?

DOCTUS — Pas tout à fait. Chaque objet a ses voyants et ses boutons : les voyants affichent la valeur des données à chaque instant, les boutons actionnent ses méthodes. Ces méthodes ne sont pas autre chose que nos anciennes procédures.

CAND. — Ainsi, la nourrice incite notre bébé à activer les bons boutons et c’est lui qui déclenche la suite des événements ?

DOC. — Leur déclenchement est effectivement conditionné par la disponibilité des boutons de commande correspondants, mais nous aurons également affaire à quelques mécanismes plus subtils. Les jouets les plus complexes contiendront des mécanismes internes que le fabricant du jouet n’a pas mis à portée de main. Ils ne concernent que le fonctionnement intime de notre objet. Par ailleurs, certains de nos objets peuvent être combinés de telle sorte que le fonctionnement de l’un en mette d’autres en action.

CAND. — On aurait donc aussi des interfaces apparentes pour les connexions entre objets. Ne deviennent-ils pas complètement dépendants les uns des autres ?

DOC. — Oui, on aboutit à...

5

Collaboration entre classes

Le but de ce chapitre est de poursuivre la découpe d’une application OO en ses classes, lesquelles jouent tout à la fois les rôles de modules, fichiers et types. Java favorise de façon très pratique cette vision et étend la relation qui existe entre les classes jusqu’aux étapes de compilation et d’exécution. C++, Python, PHP 5 et C# rendent cette mise en œuvre moins immédiate en raison d’un souci de compatibilité : avec le monde procédural (y compris le C) pour les trois premiers, avec Windows et les exécutables d’avant pour C#.

SOMMAIRE

Les classes comme fichiers reliés

La compilation dynamique

L’association de classes

L’auto-association de classes

Les paquets

CANDIDUS — J’aimerais bien rendre visite au fabricant de jouets, histoire de voir comment il construit puis emballe ce qu’il livre à notre bébé…

DOCTUS — L’organisation des fichiers en différentes catégories permet de rechercher les objets comme dans un jeu de pistes. Ils auront le même nom que l’objet qu’ils contiennent. Bébé n’aura alors qu’à utiliser des règles simples pour trouver tout ce qui lui sera nécessaire. Si le fichier contenant l’objet ne se trouve pas là où il devrait être, Bébé ne sera pas content et nous le fera savoir !

CAND. — Ne risque-t-on pas d’avoir des conflits avec des noms d’objets homonymes ?

DOC. — Bien sûr que si ! La solution consiste à utiliser les paquets, pour que chaque fabricant ait un répertoire d’entrée différent… et le tour est joué !

CANDIDUS — Bébé utilise donc les mêmes règles que le fabricant pour déduire la position des objets. Lorsqu’une pièce du puzzle en appelle une autre, il n’y a qu’à suivre la piste indiquée pour mettre la main dessus.

DOC. — Oui, et par-dessus le marché, ces règles simples font que le fabricant peut s’assurer que tous les liens entre les pièces de ses jouets figurent bien dans sa livraison. Finalement, il s’agit simplement de savoir en quoi consiste chaque objet et ce qu’on peut en attendre pour connaître entièrement ce qu’on doit en savoir. Ce n’est qu’au moment de l’emballage qu’on vérifie que tous les liens s’emboîtent correctement.

Pour en finir avec la lutte des classes

Nous avons vu dans les chapitres précédents qu’en orienté objet, il est Capital d’en finir avec la lutte des classes. Les classes ne sont pas que de simples structures d’accueil d’information ; elles sont à notre service pour...

6

Méthodes ou messages ?

Ce chapitre aborde de manière plus technique les mécanismes d’envoi de messages. Les passages d’argument par valeur ou par référent, qu’il s’agisse de variables de type prédéfini ou de variables objet, sont discutés dans le détail et différenciés dans les cinq langages. La différence entre un message et une méthode est précisée. La notion d’interface et le fait que les messages puissent circuler à travers Internet sont, à ce stade, simplement évoqués.

SOMMAIRE

Passage d’arguments dans les méthodes

Passage par valeur et par référent

Passage d’objets

Méthodes et messages

Introduction aux interfaces et aux objets distribués

CANDIDUS — Alors nos objets prennent des initiatives ? Ils communiquent par le biais de messages ?

DOCTUS — C’est exact, créer un objet consiste en tout premier lieu à définir son vocabulaire, ce qu’il peut « comprendre », à savoir l’ensemble des messages qu’il peut traiter. On appelle ça son interface. Bébé pourra jouer avec certains boutons et les objets eux-mêmes joueront les uns avec les autres de la même façon.

CAND. — Si j’ai bien observé, certains boutons messages doivent être actionnés à l’aide d’accessoires. Il me semble y reconnaître les paramètres de nos fonctions procédurales. Que se passe-t-il exactement quand un message est envoyé ?

DOC. — L’objet appelant a le choix entre donner une copie de ses informations et donner le moyen d’y accéder. La différence, c’est que l’accès à une source d’informations permet d’en changer la valeur, tandis qu’une simple copie ne le permet pas.

CAND. — Et quelle est la distinction entre message et méthode ?

DOC. — On appelle méthode ce qu’un objet exécute lorsqu’il reçoit le message associé. Les envois de messages, eux, correspondent aux appels de fonctions.

Passage d’arguments prédéfinis dans les messages

Pour envoyer un bon message, procédez avec méthode. Nous l’avons dit, un objet envoie un message à un autre avant de lui passer la main pour qu’il exécute une méthode. Lors de son exécution, comme en programmation classique, la méthode peut recevoir des arguments, qui servent à affiner ou calibrer son comportement. Considérons à nouveau la déclaration de la méthode jeTravaillePour02(int x) de la classe 02, mais qui, cette fois, prévoit de recevoir un argument de type entier, x. Cette méthode peut être activée par un message, comme dans le petit exemple suivant :

class 01 {

02 lien02 ;

void jeTravaillePour01() {

lien02.jeTravaillePour02(5) ;

}

}

Rien de particulier n’est à signaler. Ajoutons maintenant que la méthode jeTravaillePour02(int x) modifie l’argument qu’elle reçoit, comme dans le petit code Java ci-après. Tâchez, sans regarder le résultat, de prévoir ce qui sera produit à l’écran.

En Java

class 02 {

void jeTravaillePour02(int x) {

x++; /* incrément de l’argument */

System.out.println("la valeur de la variable x est: " + x);

}

}

public class 01 {

02 lien02;

void jeTravaillePour01() {

int b = 6;

lien02 = new 02();

lien02.jeTravaillePour02(b);

System.out.println("la valeur de la variable b est: " + b);

}

public static void main(String[] args) {

01 un01 = new 01();

un01.jeTravaillePour01();

}

}

Résultat

la valeur de la variable x est : 7

la valeur de la variable b est : 6

Qu’advient-il de la variable locale b, créée dans la méthode jeTravaillePour01() et passée comme argument du message jeTravaillePour02(b) ? Sa nouvelle valeur ne sera pas 7 car, en général, un passage d’argument s’effectue de manière préférentielle « par valeur ».

Cela signifie qu’une variable temporaire x est créée, dans laquelle on copie la valeur de b (6) et qui disparaîtra à la fin de l’exécution de la méthode. La variable b de départ est laissée complètement inchangée ; seule la copie est affectée. L’exécution de la méthode s’accompagne, en fait, d’une petite mémoire pile, dont le temps de vie n’est que celui de cette exécution.

Si une méthode en appelle une autre dans son corps d’instructions, les nouvelles variables propres à cette deuxième méthode se placeront dans la pile, au-dessus de celles concernant la méthode appelante. Alors que c’est l’unique type de passage permis par Java, d’autres langages ont enrichi leur offre. Lisez avec attention le code C# suivant et tentez, là encore, de prédire son résultat.

En C#

using System;

class 02 {

public void jeTravaillePour02(int x) {

x++;

Console.WriteLine("la valeur de la...

7

L’encapsulation des attributs

Ce chapitre présente les principes de l’encapsulation que, dans un premier temps, nous limiterons aux seuls attributs. Cette technique préserve l’intégrité des objets, sépare la lecture des attributs et leur stockage et contribue à stabiliser les codes.

SOMMAIRE

Private ou public

Attributs private

Encapsulation

L’intégrité des objets

Gestion d’exception

Stabilisation des codes

CANDIDUS — Certains termes de l’OO, tels « encapsulation » et « cloisonnement », me font penser à hermétisme et réglementation. Les nouveaux langages me semblaient pourtant offrir plus de souplesse !

DOCTUS — Je ne vois aucune contradiction entre souplesse et élégance. L’encapsulation est le moyen de ranger proprement le contenu de chaque objet. Il faut y voir un souci de répartition des tâches.

CAND. — Et concrètement, j’y gagnerai quoi ?

DOC. — En tout premier lieu, les accesseurs (setters et getters) doivent faire partie de l’interface des objets, qui est rigoureusement spécifiée. Il en résulte que les éléments internes, variables et méthodes, pourront évoluer sans la moindre conséquence pour les objets environnants. Et tu constateras qu’on n’y perd pas en liberté au bout du compte. Cette encapsulation n’est pas autre chose qu’un emballage, qui évite les fuites…

CAND. — … ou les intrusions. Au lieu de me servir dans les affaires de quelqu’un, mieux vaut donc lui demander poliment de l’aide. Il saura toujours mieux que quiconque où il les a rangées.

DOC. — Il saura également mieux que toi faire le nécessaire pour que tu en disposes en toute sécurité. Par exemple, il te fera attendre en cas de besoin.

CAND. — Ces objets ne se contentent pas de communiquer ; ils coopèrent, en fait !

La charte du bon programmeur OO : Arthur J. Riel

Souvent dans notre ouvrage, nous faisons référence à une supposée charte de la bonne programmation OO. Cette charte, en fait, n’existe que dans notre imagination ; ce n’est rien d’autre qu’une compilation d’un ensemble de bonnes pratiques OO acquises par la pratique. Néanmoins, il est un écrit de Arthur J. Riel qui pourrait presque prétendre à ce titre : Object-Oriented Design Heuristics (Addison-Wesley). Plus de 60 recommandations de bonnes pratiques OO y sont présentées, illustrées et défendues. En voici quelques-unes, piochées au hasard, et que vous rencontrerez pour certaines plusieurs fois dans ce livre :

• Minimisez le nombre de messages dans le protocole d’une classe.

• N’encombrez pas la partie publique d’une classe avec des choses que les utilisateurs de cette classe ne sont pas aptes à utiliser ou dont ils ne voient pas l’intérêt.

• Une classe capture une et une seule abstraction.

• Ne créez pas de classes « God » dans votre application. Soyez très sceptiques devant toute classe s’appelant en partie « Pilote », « Manager », « Système » ou « Sous-Système ».

• Méfiez-vous des classes contenant beaucoup...

8

Les classes et leur jardin secret

Ce chapitre poursuit l’exposé de la pratique de l’encapsulation en l’étendant aux méthodes. Il sépare l’interface d’une classe de son implémentation. Il justifie cette encapsulation par la stabilisation des développements qu’elle apporte. Il discute les différents niveaux d’encapsulation rendus possibles dans les langages de programmation. Il termine par une petite allusion aux systèmes complexes dont se rapproche tant la pratique de l’OO, laquelle contribue à les maîtriser.

SOMMAIRE

Méthode publique ou privée

Interface et implémentation

Améliorer la stabilité des développements

Niveaux intermédiaires d’encapsulation : amitié, héritage, paquet, classes imbriquées

L’effet papillon dans les systèmes complexes

DOC. — Nous avons toute liberté de modifier un mécanisme interne à un objet, et même les méthodes publiques qui font partie de l’interface. Il s’agit juste de dire à un objet ce qu’on attend de lui sans pour autant lui dire comment il doit s’y prendre ! C’est lui qui doit savoir comment implémenter la chose, avec ses propres méthodes privées. L’héritage lui-même doit être réglementé, les parents doivent pouvoir décider de ce qu’ils gardent pour eux.

CAND. — Je pourrais donc appliquer ce même principe de cloisonnement face aux utilisateurs de mes classes ! Ils n’hériteront que des méthodes que j’aurai choisi de mettre à leur disposition.

DOC. — On peut également constituer des relations de groupe. Des classes d’objets travaillant en équipe pourront utiliser un vocabulaire commun tout en restant inaccessibles au public, comme des amis qui parlent entre eux alors que l’entourage n’est pas du tout concerné. Encore plus fort : dans une voiture, le volant, l’accélérateur et le frein peuvent n’exister que pour « l’objet » conducteur.

CAND. — Hmmm… Ton conducteur me fait penser à un chauffeur esclave de sa voiture qui attend ses ordres pour pouvoir s’amuser sur ses pédales.

DOC. — On peut effectivement faire dans le genre poupées russes : des objets complètement imbriqués les uns dans les autres. Autre direction maintenant : après la fermeture de nos boîtes noires pour interdire l’accès à leurs rouages internes, il faudra également prévoir de les interconnecter pour construire notre système. Il nous restera à doser raisonnablement la complexité des branchements du réseau de communications entre tous ces objets, pour éviter les cascades d’événements inextricables !

Encapsulation des méthodes

Idéalement, même la simple lecture des attributs ne devrait que très rarement constituer le contenu d’une méthode publique. Le plus souvent, les autres classes modifient ces attributs ou les utilisent à travers une méthode, afin qu’à partir de la valeur de ceux-ci, une nouvelle...

Index

Symboles

.Net 142, 390, 423, 506

Numeriques

2-tiers 403

3-tiers 403

A

abstract 316

Abstract Factory 623

abstraction 312

Access 500

acteur 57

ActionListener en Java 379

adressage indirect 6, 92

affectation d’objet 362, 363

agrégation 185

analyse

objet 56

procédurale 54

annuaire 421, 435

argument 64, 184

objet 91, 140

passage par référent 86, 89

assemblage 79, 128

association de classes 61, 176

atome 600

attribut 2, 61, 62

private 109, 110

automate cellulaire 442

B

base 278

base de données 403, 454, 499

objet 60

OO 521, 523, 524

relationnelle 5, 499

relationnelle-objet 60, 512, 517

Berners-Lee, Tim 423

biologie 60, 442

Booch, Gary 160

Bridge 623

C

cardinalité 176

cas d’utilisation 160

casting...