|
Partie 1
C#, un langage objet
1. C'est quoi, un langage objet ?
Vous le savez sans doute déjà : C# est un langage objet.
Ce n'est pas le seul : C++, Java, Visual Basic, pour ne
citer que les plus connus, sont eux aussi des langages objets.
Ces langages, apparus dans les années 1990, s'oppose à ceux de
la génération précédente, qui étaient dits « procéduraux »
(comme le Cobol, le Fortran, le Pascal, le C et bien d'autres,
on ne va pas tous les citer, on n'a pas que cela à faire non
plus).
La première chose à dire des langages
objet, c'est qu'ils permettent de faire tout, absolument
tout, ce qu'on pouvait faire avec un langage procédural.
Donc, et c'est la bonne nouvelle du jour, rien de ce que vous
avez appris n'est perdu ! Les langages objet, comme leurs
ancêtres les langages procéduraux, manipulent des variables,
des tableaux et des structures, et organisent des instructions
d'affectation, d'entrée-sortie, de tests ou de boucles dans
des procédures et des fonctions. Donc, à la limite, on peut
(presque) programmer en langage objet exactement comme on
programmait en langage procédural. Mais évidemment, ce serait
bien dommage, car on passerait alors à côté de ces petits
riens que les langages objet possèdent en plus, et qui vont
nous changer la vie...
Remarque
sournoise :
S'il y a quelque chose que vous ne comprenez pas dans le
paragraphe qui précède, c'est vraisemblablement que vous avez
doublement brûlé les étapes.
D'une part, en voulant apprendre C# sans avoir appris
l'algorithmique.
D'autre part, en n'ayant pas lu assez attentivement les Préambules
nécessaires (ce qui n'est pas bien) ou en les ayant lu,
et en choisissant de les ignorer (ce qui est encore
pire).
Dans les deux cas, vous n'échapperez pas à un retour par la case départ, et vous ne
touchez pas 20 000 F.
Reprenons. Les langages objet, tout en intégrant l'ensemble
des capacités des langages procéduraux, possèdent deux
aptitudes supplémentaires, aptitudes liées mais distinctes.
Ces langages peuvent en effet :
- gérer, en plus des variables, des tableaux et des
structures, des choses appelées objets.
- exploiter l'interface graphique
de Windows.
Remarque
culturelle :
Le nom des langages objets est censé suggérer cette montée en
puissance par rapport aux langages traditionnels. C'est ainsi
que le plus célèbre des langages procéduraux, le C, a donné
naissance à deux principaux avatars objets.
- le C++, c'est-à-dire le « C augmenté de 1 », puisqu'en
C, l'instruction ++ incrémente la variable qui le précède
d'une unité.
- le C#, qui est un clin d'oeil (d'oreille ?) aux
musiciens : en anglais, C correspond à notre note Do. Le
C#, c'est donc le do dièze, situé juste au-dessus du do.
Et après ça, on dira que les informaticiens ne sont que des
geek bouffeurs de pizza et incapables de toute poésie...
Reprenons. On verra plus tard que par contamination, les
langages objet ont tendance à tout assimiler à des objets,
même des choses qui au départ, n'en étaient pas spécialement,
comme les bonnes vieilles variables de notre enfance. Mais
n'anticipons pas, et examinons tout d'abord les deux points
ci-dessus plus en détail.
1.1 Qu'est-ce qu'un objet ? Parlons comme les gens
normaux
Dans la vie de tous les jours, nous sommes entourés d'objets.
Certains très simples, comme un peigne, un bouton de culotte
ou une matraque de CRS. D'autres très complexes comme une
automobile, un ordinateur ou une navette spatiale. Pour faire
l'analogie avec les objets des langages objet, mieux vaut
penser à un objet un peu compliqué qu'à un objet trop simple.
Et pour cette analogie, rien ne nous oblige à penser à un
objet inanimé. Des plantes, des animaux ou des êtres humains
peuvent tout à fait être assimilés aux objets que manipulent
les langages.
Dans les objets, il y a trois sortes de choses qui
intéressent les informaticiens.
- ils possèdent des caractéristiques
(une couleur, une taille, un poids, un compte en banque, un
nombre de pattes, bref, que sais-je encore). Un objet très
simple peut avoir une seule caractéristique (voire aucune,
mais là, on peut raisonnablement se demander s'il existe -
je laisse cette question aux philosophes désoeuvrés). Un
objet complexe peut posséder des centaines, voire des
milliers de caractéristiques.
- ils peuvent accomplir certaines tâches
sur demande, ou subir certaines
modifications : une automobile peut voir son moteur
tourner plus ou moins vite, Un chat peut marcher, courir,
miauler, ronronner, etc. Un employé peut travailler, changer
de bureau, engueuler son collègue, etc.
- ils peuvent réagir automatiquement à
certains événements : une automobile se met à
hurler si on essaye de fracturer la serrure, un chien aussi
si le facteur sonne à la porte, le chat court s'il voit une
souris, etc.
Tous les objets possédant les mêmes caractéristiques,
capables d'accomplir les mêmes tâches sur demande et de réagir
automatiquement aux mêmes évènements forment un groupe qu'on
appelle en informatique une classe.
Par exemple, tous les chiens, et c'est à cela qu'on les
reconnaît, ont une couleur de pelage, une taille, un poids,
etc. Ils peuvent tous aboyer, courir, sauter, etc. Ils ont
donc en commun de posséder certaines caractéristiques et de
pouvoir effectuer certaines actions, et font donc partie d'une
classe unique que j'appelle « les chiens ». Cela
n'empêche nullement chacune de ces aptitudes d'être différente
d'un chien à l'autre : le chihuahua de ma cousine est très
différent du rottweiler de mon voisin, ma cousine en sait
quelque chose lorsqu'elle croise mon voisin. Il n'empêche :
tous deux sont des chiens, et pas des porte-manteaux ou des
téléviseurs (qui, eux aussi, ont des tailles, des poids et des
aptitudes différentes selon les modèles).
En prenant le problème à l'envers : si je définis une
classe par l'ensemble de ses caractéristiques et de ses
actions, je peux, à partir de cette classe, fabriquer tout
plein de toutous différents les uns des autres, mais qui
auront en commun d'être tous des chiens (donc, répétons-le
lourdement, des êtres qui partageront les mêmes
caractéristiques et qui seront capables des mêmes actions).
Eh bien, les langages objet, ce sont des langages qui
permettent, en plus des traditionnels variables, tableaux et
structures, de gérer et de manipuler des objets (donc des
classes). C'est-à-dire que ces langages permettent
notamment :
- de créer des classes, en définissant les caractéristiques
et les actions dont seront capables les objets qui en seront
issus
- de fabriquer des objets à partir de ces classes
- de manipuler les caractéristiques individuelles de chacun
de ces objets, et de leur faire accomplir les actions dont
ils sont capables.
Tout ce que nous avons vu là peut être traduit dans des
termes techniques propres aux informaticiens.
1.2 Qu'est-ce qu'un objet ? Parlons comme les
informaticiens
Nous savons que tout programme informatique a pour but de
manipuler des informations. Et nous savons que ces
informations relèvent toujours, au bout du compte, de l'un des
trois grands types simples :
numériques, caractères (alphanumériques), ou booléens.
Lorsque nous disons qu'un objet (ou une classe) possède des
caractéristiques comme la taille, le poids, la couleur, etc.,
nous disons en fait qu'un objet (ou une classe) regroupe un
certain nombre de variables :
une variable numérique pour stocker le poids, une autre
variable numérique pour stocker la taille, une variable
caractère pour stocker la couleur, etc.
Donc, première chose, un objet regroupe un ensemble de
variables qui peuvent être de différents types. Et dans ce
cas, on ne parlera pas des « variables » d'un objet,
ni des ses « caractéristiques », mais de ses propriétés (ou encore, de ses attributs).
Définition :
Une propriété d'un objet est une des variables (typée)
associées à cet objet.
Théorème :
Par conséquent, toute instruction légitime avec une variable
est légitime avec une propriété d'un objet. Et lycée de
Versailles, tout ce qui n'avait pas de sens avec une variable
n'a pas non plus de sens avec une propriété d'un objet.
Mais tout cela, allez-vous dire, n'est qu'une manière de
faire mousser avec du vocabulaire nouveau une notion bête
comme chou et bien connue depuis longtemps. Parce qu'enfin,
quoi, un bidule constitué de différentes variables de
différents types, on n'a pas attendu les objets pour en avoir.
Tous les langages procéduraux connaissent cela, mis à part
qu'on ne parle pas de classe mais de structure,
qu'on ne parle pas d'objets, mais de variables
structurées, et qu'on ne parle pas de propriétés,
mais de champs. Mais pour le reste,
c'est tutti quanti et du pareil au même.
Les esprits chagrins qui feraient cette remarque auraient
parfaitement raison... si les objets n'étaient effectivement
qu'un ensemble de caractéristiques (de propriétés). Mais les
objets ne sont pas que cela : ils incluent également,
comme on l'a vu, des actions
possibles. Autrement dit, un objet (une classe) est un
assemblage d'informations (les propriétés) mais aussi
d'instructions (les actions, que l'on appelle les méthodes)
et de réactions automatiques à des évéments.
C'est la présence de ces méthodes et de ces événements qui
différencie une classe d'une simple structure, et un objet
d'une simple variable structurée.
On peut donc dire qu'une classe, c'est
une structure plus des méthodes (procédures et fonctions) et des événements.
Définition :
Une méthode est un ensemble d'instructions associé à un objet
(et à sa classe).
Toute méthode est donc une procédure ou une fonction.
Nous mettons donc dès à présent le doigt sur la différence
profonde qui existe entre un langage procédural traditionnel
et un langage objet : il s'agit de la manière dont sont
articulées les informations et les traitements permettant de
les modifier.
- dans un langage procédural, il existe une séparation
rigoureuse entre les informations et les traitements. Au
cours de l'exécution d'un programme, les informations sont
stockées des conteneurs spécifiques (variables, tableaux,
structures) et les traitements (instructions) agissent sur
ces informations, si j'ose dire, « du dehors ».
- dans un langage objet, on a regroupé
dans une même entité (la classe, donc les objets qui en sont
issus) les propriétés et les méthodes, c'est-à-dire les
informations et les instructions qui permettent de les
manipuler.
2. La syntaxe objet
2.1 Généralités
Lorsque nous fabriquions (et nous en fabriquerons encore)
une variable, nous utilisions un « moule » à
variable, qui s'appelle un type.
Pour créer une nouvelle variable, il fallait préciser le
type utilisé pour la fabrication de cette variable, par
exemple un entier, et lui donner un nom par lequel on la
désignerait ensuite tout au long du programme. Dans de
nombreux langages– dont le C# – il est même possible de
l'affecter directement à la création, par exemple par la
valeur 100. D'où la syntaxe :
int toto = 100;
En ce qui concerne les objets, le principe est exactement
le même, hormis qu'on ne les fabrique pas d'après un type,
mais d'après une classe. Si nous
disposons par exemple d'une classe Chien,
nous allons pouvoir créer autant de chiens individuels que
nous voulons. Voilà par exemple un nouveau compagnon :
Chien Rantanplan
= new Chien();
On remarque la présence du mot clé new,
propre aux déclarations d'objets, et qui différencie
celles-ci des déclarations de variables. On remarque aussi
la présence d'une paire de parenthèses après le nom de la
classe, ce qui nous évoque irrésistiblement un appel de
procédure ou de fonction. Dans le jargon du langage objet,
cette instruction new s'appelle un
constructeur. Et la réalité est bel
est bien conforme aux apparences : en créant un nouvel objet
d'après une classe, nous appelons en effet une procédure –
plus précisément, une méthode –,
le constructeur en question. Dans le cadre de ce cours, nous
n'entrerons pas davantage dans ces détails, mais rien ne
vous empêche de fouiner le Net pour en apprendre davantage.
Vocabulaire
savant :
Créer un objet d'après une classe s'appelle instancier
la classe.
Un objet peut aussi être appelé une instance,
ou une occurrence, de la classe.
Notre classe Chien a forcément
été créée avec un certain nombre de propriétés et de
méthodes. Pour chaque objet instancié selon cette classe,
nous pouvons accéder à ces propriétés et à ces méthodes par
la syntaxe suivante, universelle :
NomObjet.NomPropriété
Et également :
NomObjet.NomMéthode
Remarque
fondamentale :
Dans un langage objet, on ne peut rencontrer que les deux
syntaxes ci-dessus.
Sauf dans des cas exceptionnels, il est impossible de
désigner un objet sans le faire suivre d'une propriété ou
d'une méthode. C'est une faute de syntaxe.
De même, on ne trouvera jamais une propriété ou une méthode
seules, non précédées de l'objet auxquelles elles se
réfèrent.
Remarque
fondamentale :
En fait, il y a une troisième circonstance importante dans
laquelle on va retrouver une forme
« NomObjet.UnTruc ». Mais chaque chose en son
temps.
2.2 Propriétés
Admettons pour les besoins de la cause que notre classe Chien possède entre autres
propriétés :
- Taille (float)
- Poids (integer)
- Couleur (string)
- Vacciné (bool)
Alors, je le rappelle, ces propriétés étant en réalité des
variables – les champs d'une structure – les règles de leur
utilisation sont très exactement les mêmes que celles des
variables. Sachant que le signe d'affectation, en C#, est le
signe d'égalité, je peux donc écrire :
Rantanplan.Poids = 14;
Et je viens de fixer le poids de mon toutou à 14 kg. Pour
le faire grossir de 5 kg, rien de plus simple :
Rantanplan.Poids = Rantanplan.Poids + 5;
...et le tour est joué. Si je veux torturer la pauvre bête,
je peux aussi la rendre aussi lourde que haute, en
écrivant :
Rantanplan.Poids = Rantanplan.Taille;
L'utilisation de propriétés non numériques ne pose pas
davantage de problèmes :
Rantanplan.Couleur = "Beige";
Rantanplan.Vacciné = True;
2.3 Méthodes
Faut-il le répéter, les méthodes sont des fonctions ou des
procédures qui ont été définies pour tous les objets d'une
classe donnée. Utiliser convenablement une méthode suppose
donc de respecter la manière dont la procédure ou la
fonction a été écrite. En particulier, comme à chaque fois
en pareil cas, il va falloir respecter le nombre et le type
des paramètres dont la méthode (la procédure, la fonction) a
besoin pour s'exécuter. Ainsi, certaines méthodes
peuvent-elles être utilisées sans passer de paramètres.
D'autres en exigeront un, d'autres deux, etc.
Lorsque la méthode est un appel de procédure, elle
représente en elle-même une instruction à part entière.
Lorsqu'elle est un appel de fonction, elle renvoie un
résultat. Dans tous les cas, il
serait parfaitement absurde d'affecter une méthode comme
on affecte une propriété. Les appels aux méthodes
pourront donc donner lieu à des lignes du genre :
Rantanplan.Aboyer();
...si la méthode Aboyer s'emploie
sans arguments,
Rantanplan.Courir(15);
...si la méthode Courir nécessite
un argument numérique, celui fixant la vitesse de course,
Rantanplan.DonnerlaPapatte("gauche");
...si la méthode DonnerlaPapatte
réclame un argument de type caractère, etc.
Si vous avez compris cela, vous avez compris 45 % de ce
cours. Très exactement, au millipoil près.
3. La programmation événementielle
Nous ne sommes pas au bout de nos peines (ni au bout de nos
joies). Toute cette histoire d'objets cache une autre
plaisanterie, à laquelle j'ai déjà brièvement fait allusion.
Celle-ci va radicalement transformer la manière dont les
procédures d'un programme vont être exécutées, et du coup,
la manière dont les programmeurs vont devoir concevoir leurs
applications. Alors, de quoi s'agit-il ?
Rappelons-nous comment notre code était organisé dans un
langage procédural traditionnel. Plutôt qu'une immense
procédure fait-tout, comportant des redites de code, nos
applications, dès lors qu'elles devenaient un peu joufflues,
étaient organisées en modules séparés : sous-procédures
et fonctions (lesquelles, je le rappelle, ne sont jamais
qu'un cas particulier de sous-procédures).
Parmi ces diverses procédures, il s'en trouvait une qui
jouait un rôle particulier : la procédure principale
(appelée Main dans la plupart des langages). C'est elle qui
était exécutée lors du lancement de l'application. Et c'est
elle qui tout au long du programme, telle un chef
d'orchestre, déclenchait les autres procédures et les autres
fonctions.
Le point important dans cette affaire, c'est qu'une fois
l'application lancée, une procédure
donnée ne pouvait s'exécuter que si une ligne de code,
quelque part, en commandait le déclenchement.
L'utilisateur n'avait aucune espèce de moyen d'influencer
directement l'ordre dans lequel les procédures allaient être
exécutées.
Tout ceci est remis en question avec les langages objet.
Non qu'on ne puisse plus créer des procédures et des
fonctions traditionnelles, et appeler les unes via les
autres par des instructions adéquates ; je le rappelle,
il n'y a rien qu'on pouvait faire avec un langage procédural
qu'on ne puisse faire avec un langage objet. Mais avec un
langage objet, on va pouvoir faire certaines choses
véritablement inédites. En l'occurrence, la grande
nouveauté, c'est qu'on va pouvoir
organiser le déclenchement automatique de certaines
procédures en réponse à certaines actions de l'utilisateur
sur certains objets. Et ces actions, ce sont les
fameux événements dont je parlais
tout à l'heure.
Pour comprendre cela, le plus simple est de penser à
certains objets, qui possèdent un signe particulier :
ils se voient à l'écran. Un système d'exploitation tel que
Windows est truffé de ce genre d'objets ! Les boutons,
les menus, les fenêtres, les cases à cocher, tout cela
constitue une armada d'objets visibles, et surtout, capables
de réagir aux sollicitations de l'utilisateur via le clavier
ou la souris. Les programmeurs qui ont écrit Windows ont
donc prévu, et écrit, des myriades de morceaux de code (des
procédures) qui se déclenchent à chaque fois que
l'utilisateur accomplit telle action sur tel type d'objet,
par exemple, le clic sur un bouton, le double-clic sur un
raccourci, etc. Donc, concevoir une application
événementielle, c'est concevoir des
procédures qui se déclencheront automatiquement à chaque
fois que l'utilisateur effectuera telle action sur tel
objet qu'on aura mis à sa disposition.
Remarque
profonde :
Dans les phrases qui précèdent, les mots « à chaque
fois que » sont essentiels. Il faut
impérativement les avoir en tête lorsqu'on écrit une
application objet.
Faute de quoi on mélange tout, et en particulier, on se met
à écrire des boucles là où il n'y a qu'une simple procédure
événementielle.
Définition :
Une action capable de provoquer la réaction d'un objet donné
– c'est-à-dire, de déclencher une procédure donnée liée à
cet objet – s'appelle un événement.
Voilà pourquoi ce type de programmation porte le nom de programmation événementielle. Par
ailleurs, je rappelle que les événements qu'un objet donné
est capable de gérer ont été définis dans la classe qui a
servi à créer l'objet.
Remarque
importante :
Tous les objets capables de gérer un événement ne sont pas
forcément des objets visibles à l'écran. Dans le même ordre
d'idées, tous les événements ne correspondent pas forcément
à des actions de l'utilisateur via le clavier ou la souris.
Mais pour commencer, on peut très bien s'accommoder de ces
approximations.
3.1 Le diagramme T.O.E.
Lors de la conception d'un programme objet, une des
premières tâches du développeur va donc être de concevoir
l'interface utilisateur. C'est-à-dire de prévoir quels
objets vont être mis à sa disposition à l'écran, quelles
seront les actions qu'il pourra effectuer sur ces objets
(c'est-à-dire les événements qu'il pourra déclencher) et de
prévoir les tâches que le programme devra accomplir lors de
ces événements.
Pour le moment, nous nous contenterons de considérer que
nos applications emploient uniquement l'arsenal des objets
utilisés par Windows. Ces objets (plus exactement, ces
classes) seront donc tout prêts à l'emploi. Leurs
propriétés, leurs méthodes et les événements qu'ils sont
capables de gérer ont été définis par Windows, plus
exactement par le Framework .NET
(une couche logicielle qui sert d'intermédiaire entre C# et
Windows, qui parle un langage trop abscons pour nous).
En réalité, dans un programme C#, on peut utiliser des tas
d'autres objets (classes) et on peut même en fabriquer
soi-même. Nous verrons cela... un peu, et plus tard. Pour le
moment, on se contentera de la trousse à outils que le
Framework .NET met à notre disposition, ce qui suffira déjà
à nous procurer de longues heures de bonheur.
Ainsi, nous pouvons prévoir qu'il faudra que la fenêtre de
notre application se présente comme ceci ou comme cela,
qu'il devra y avoir ici un bouton, là des boutons radios,
ici une zone de liste, etc. Et il faut également prévoir
qu'un clic sur tel bouton déclenchera tel ou tel calcul,
qu'un choix dans telle liste devra mettre à jour telle ou
telle zone, etc.
Le document synthétique, sous forme de tableau, qui reprend
toutes ces informations, s'appelle un diagramme
T.O.E., pour Tâche, Objet, Événement. C'est un
document préalable indispensable à la programmation d'une
application événementielle. Il comporte trois colonnes. Dans
la première, on dresse la liste exhaustive des tâches que
doit accomplir l'application. Dans la seconde, en regard de
chaque tâche à accomplir, on porte, le cas échéant, le nom
de l'objet qui en sera chargé. Et dans la troisième, en
regard de chaque objet, on écrit le cas échéant, mais oui,
l'événement correspondant. Vous l'aviez deviné ?
Décidément vous êtes trop forts.
Remarque
importante :
Rien n'impose qu'un objet soit associé à un événement et à
un seul. Certains objets peuvent fort bien n'être associés à
aucun événement. De même, d'autres objets peuvent très bien
gérer plusieurs événements différents, qui correspondront
donc à autant de procédures différentes.
Nous verrons très bientôt comment crééer une procédure
événementielle en C#. En attendant, si vous avez compris le
mécanisme des procédures événementielles, alors vous avez
alors pigé 45 % supplémentaires du cours. Donc, avec les 45
% précédents (ceux des classes, des objets, des propriétés
et des méthodes), on en est à 90 %. Tout le reste,
c'est de la petite bière. Puisque je vous le dis.
|