Ce chapitre ne concerne pas seulement Java mais tout langage orienté objet. Il donnera les notions et le vocabulaire fondamentaux de l'OO.
Il existe deux grands types de programmation :
Le Procédural ou structuré comme le C où on définit des fonctions s'appelant mutuellement. Chaque fonction ou procédure est associée à un traitement particulier qui peut être décomposé en sous traitements jusqu'à obtenir des fonctions basiques. Globalement, le procédural travaille sur l'action ou le verbe. Par exemple, pour calculer la vitesse d'une voiture, la philosophie du procédural conduira à faire : calculVitesse(voiture) partout où cela est nécessaire. Le code faisant référence à une voiture est donc "fondu" et dispersé dans l'ensemble des programmes.
L'Orienté Objet ( ou OO ) où on manipule uniquement des objets c'est-à-dire des ensembles groupés de variables et de méthodes associées à des entités intégrant naturellement ces variables et ces méthodes. Dans cette configuration, le sujet est prépondérant: disposant d'un objet Voiture, on effectuera spontanément : Voiture.calculVitesse() . Tout le code touchant à l'objet Voiture se trouve ainsi regroupé.
L'OO supplante peu à peu le procédural dans les grands programmes car il présente d'énormes avantages: facilité d'organisation, réutilisation, méthode plus intuitive, possibilité d'héritage, facilité de correction, projets plus faciles à gérer. L'intérêt principal de l'OO réside dans le fait que l'on ne décrit plus par le code des actions à réaliser de façon linéaire mais par des ensembles cohérents appelés objets.
L'OO est facilement concevable car il décrit des entités comme il en existe dans le monde réel. Ainsi, l'objet Voiture qui implémente la méthode Voiture.rouler et possède la propriété Voiture.Cylindrée est facilement concevable et peut être utilisée -par exemple- dans une simulation de course automobile où on fera interagir plusieurs objets Voiture. Les modèles à objets ont été créés pour modéliser le monde réel. "Dans un modèle à objets, toute entité du monde réel est un objet, et réciproquement, tout objet représente une entité du monde réel".
L'OO permet en quelque sorte de factoriser le code en ensembles logiques. Du point de vue de la programmation, L'OO permet d'écrire des programmes facilement lisibles avec un minimum d'expérience, de taille minimale et à la correction aisée. Ces programmes sont, de plus, souvent très stables.
Les informations concernant un domaine étant centralisées en objets, il est facile de sécuriser le programme en interdisant ou autorisant l'accès à ces objets aux autres parties du programme.
En général, en OO, cohabitent deux types de développeurs: ceux qui conçoivent les objets et ceux qui utilisent ces objets dans leurs programmes. De cette façon, la programmation objet permet de diviser la complexité. La programmation objet permet d'obtenir des projets stratifiés. Chaque protagoniste ne travaille que sur des implémentations le concernant.
Une classe encapsule, c'est-à-dire regroupe des propriétés et des comportements. Par exemple, la classe Humain définit des propriétés ( deux bras, deux jambes...) et des comportements ( marcher, parler, voir...).
classe Humain
En OO, les comportements sont appelés méthodes et les propriétés variables d'instance. Notons que les propriétés des classes peuvent elles-même être des objets. Par exemple, la propriété bras de notre exemple peut être un objet de type 'Bras'. Si nous prenons l'exemple d'une voiture, la classe 'Voiture' sera l'ensemble des plans de la voiture.
Un objet est une instance de classe, c'est-à-dire un exemplaire utilisable crée à partir de cette classe et en valorisant certaines propriétés. Par exemple, bob ou bill sont des instances de la classe Humain, c'est-à-dire des humains ayant des propriétés spécifiques ( bob est un humain aux yeux noirs et bill un humain aux yeux marrons ). Notons que le concept de classe est abstrait : personne n'a jamais vu d'Humain dans la nature alors que le concept d'objet est fondamentalement concret : il est concevable de croiser des personnes physiques, c'est-à-dire des instances d'Humain.
Tout objet possède un type: bob est de type Humain. L'instance d'une classe est du type de sa classe. C'est le type initial de l'objet. La classe est le moule, le plan, la recette de tout objet. La plupart du temps, les objets sont initialisés lors de leur instanciation. Le système exécute alors automatiquement le constructeur de la classe. Le constructeur est exécutée à l'instanciation de l'objet. Il prend en argument des propriétés du nouvel objet. L'instanciation d'une voiture rouge se fait par Voiture(rouge). Une classe peut avoir plusieurs constructeurs. Dans notre exemple, on peut instancier une Voiture en ne lui précisant que sa couleur ( exemple précédant ) ou en lui précisant en plus sa marque de fabrique : Voiture(rouge,Renault) Toujours dans notre exemple de voiture, une instance de Voiture sera physiquement une voiture - unique - qui a été construite à partir du plan 'Voiture'.
Dans les programmes, un objet est une zone mémoire qui est pointée par une ou plusieurs références. Une fois l'objet instancié, il correspond en réalité à une zone mémoire donnée. Cette zone mémoire, pour être utilisée doit être référencée. Par exemple, bob est une référence sur l'objet de type Humain correspondant et vaut l'adresse mémoire E515:FB80 . Instancions l'objet bill : il y a réservation d'une seconde place mémoire référencée ( pointée) par la référence bill valant E515:FF90. Un objet peut posséder plusieurs références: par exemple, si on fait bill = bob, cela signifie qu'ils référencent tous les deux le même objet, la même zone mémoire. Dans ce cas, l'objet bill est donc perdu car il n'est plus référencé. Les références bill et bob désignent maintenant le même objet. Dans la suite de ce document et pour améliorer la compréhension, nous désignerons par abus de langage une référence sur un objet par le terme 'objet'. Par exemple: "l'objet Bill de type Humain" au lieu de "la référence Bill sur l'objet correspondant de type Humain". Dans l'exemple de la voiture, une référence sur un voiture pourrait être sa plaque d'immatriculation.
L'héritage permet de spécialiser une classe qui possédera non seulement les propriétés et méthodes de sa mère mais également d'autres méthodes spécifiques ou redéfinies. Le terme est faire dériver la classe en une classe fille. Dans l'objet fille, on trouve:
De nouvelles méthodes ou propriétés
Des méthodes ou propriétés qui surchargent, c'est-à -dire redéfinissent celles de la classe mère.
Les propriétés et méthodes de la classe mère qui n'ont pas été surchargées
Remarque: Les méthodes et propriétés peuvent être héritées à un niveau n, c'est-à-dire qu'un objet peut utiliser une méthode de la mère de sa mère et ainsi de suite. Exemple d'héritage :
Les classes Voiture et Moto dérivent de la classe Véhicule.
Voiture :
Conserve la méthode rouler() de Véhicule
Conserve la propriété Couleur de Véhicule
Surcharge la méthode seGarer de Véhicule
Implémente la méthode reculer()
Possède la nouvelle propriété Volant
Moto:
Conserve la méthode seGarer() de Véhicule
Conserve la méthode
rouler() de Véhicule
Conserve la propriété Couleur de Véhicule
Implémente la méthode passerEntreLesVoitures()
Possède la nouvelle propriété Guidon
Les objets sont dits polymorphes car ils possèdent plusieurs types: le type de leurs classes et les types des classes ascendantes. Par exemple, uneHonda, instance de Moto aura comme type initial Moto mais une Moto possède par héritage le type Véhicule. L'objet uneHonda est bien un Véhicule. Dans certains cas, il est possible de forcer le programme à 'voir' un objet comme un type différent de son type initial, c'est le transtypage ou cast. Ce transtypage ne modifie par l'objet mais indique seulement la façon de le voir. Il y a transtypage implicite de la fille vers la mère: une Voiture est implicitement de type Véhicule.
Attention! Une erreur courante est de penser qu'il y a cast de la mère vers la fille: Une classe mère n'est pas du type de sa fille! Un Véhicule n'est pas forcement une Voiture. Dans certains cas, nous avons besoin d'affecter une variable d'un type à une autre d'un autre type. De nombreux problèmes métaphysiques s'en suivent généralement. La bonne façon de raisonner lorsque l'on veut affecter un type à un autre est de procéder comme suit:
On fait A <- B ; A possède un type initial, le type que l'on a donné à l'instanciation. Cette affectation est valide si et seulement si B est du type initial de A. Autrement dit, il faut que B soit de même type initial que A ou d'un type dérivé de celui de A. Exemple:
monVehicule est une instance de
type Véhicule;
maVoiture est une instance de
type Voiture;
maVoiture <- monVehicule : est-ce
une affectation valide?
maVoiture est de type initial Voiture ; monVehicule est de type initial Véhicule et un Véhicule n'est pas forcement une Voiture donc cette affectation n'est pas valide. En revanche étudions l'affectation : monVehicule <- maVoiture :
maVehicule est de type initial Véhicule et maVoiture est également de type Véhicule car Voiture dérive de Véhicule; donc cette affectation est valide !
Le terme polymorphisme est également souvent associé par abus de langage au concept de polymorphisme paramétrique: un objet peut comporter plusieurs méthodes de même nom et possédant des arguments différents. Ce sont des méthodes polymorphiques. Nous en avons vu un exemple avec les constructeurs.
Voiture.rouler(chemin)
la façon dont la voiture roule ne dépend que du
chemin.
Voiture.rouler( chemin,meteo) la façon dont
la voiture roule dépend du chemin et de la
météo.
Voiture.rouler(chemin,meteo,circulation)
la façon dont la voiture roule dépend du chemin, de
la météo et de la circulation.
Il existe deux types de transtypage:
Le transtypage ascendant qui sert à un objet à être vu comme du type de sa mère. Ce transtypage est fait de façon implicite et n'est nécessaire que dans le cas où la classe courante possède une propriété ayant le même nom que sa classe mère et que l'on cherche à accéder à la propriété mère. ( ce transtypage rarement utilisé est illustré au chapitre 06 ).
Le transtypage descendant - le plus courant - qui sert à forcer une classe de type mère à être vue comme un type fille. Ce transtypage n'est valide que si l'objet de type mère était de type fille à son instanciation.
Donnez la signification des termes suivants ( donner des exemples ):
Instance - objet - classe - méthode - comportement - propriété - surcharge - transtypage - héritage - classe fille - classe mère - type - référence - polymorphisme - constructeur.
Quels sont les principales différences entre la programmation objet (comme le Java) et procédural (comme le C) ?
Quels sont les avantages de la programmation OO ?
Quels sont les deux types de services que on rencontrer dans une structure développant OO en entreprise ?
Quelles sont les différences entre une classe et un objet ?
Comment obtenir un objet en vue de l'utiliser ?
Qu'est ce que le polymorphisme ? le polymorphisme paramétrique ?
A quoi sert l'héritage?
Qu'est ce que le transtypage? Le transtypage modifie-t-il l'objet ?
Quelle est la différence entre type à l'instanciation et type acquis par cast (inné et acquis en quelque sorte ) ?
A quelle condition peut-on transtyper à coup sûr un objet d'un type vers un autre type?
Dans cet exercice, nous noterons (Toto)Titi comme le transtypage de Titi en type Toto.
La classe Voiture dérive de la classe Véhicule.
Soit le programme suivant se trouvant dans une classe quelconque: ( les notations ne correspondent pas à celles d'un véritable langage de programmation).
classe Véhicule méthode seGarer(){ |
classe Voiture dérive de Véhicule{ méthode klaxonner(){ méthode rouler(){ |
Soit une106, une instance de Voiture et monVehicule, une instance de Véhicule.
1- Peux-t-on faire une106.rouler() ? Pourquoi ?
2- Si l'on fait une106.seGarer(), est-ce la méthode de la classe Véhicule ou de la classe Voiture qui est appelée ?
3- Peux-t-on faire monVehicule.klaxonner() ? Pourquoi ?