Les attributs
On appelle attribut d’un objet une information qui spécifie une caractéristique d’un objet. L’ensemble des attributs d’un objet permet de caractériser précisément l’état d’un objet.
Les méthodes
On appelle méthode d’un objet une routine s’appliquant à cet objet en particulier.
Qu’est-ce qu’une classe
Une classe est une définition des caractéristiques communes d’un ensemble d’objets. Elle contient, entre autres, l’ensemble des attributs et des déclarations de méthodes que ces objets ont en commun.
Les constructeurs
Méthodes spéciales d’un objet permettant d’initialiser l’état initial de l’objet. En général, le but d’un constructeur est d’assigner les attributs de l’objet.
Plusieurs langages objets permettent la création de plusieurs constructeurs afin d’initialiser différemment l’état de l’objet. Si tel est le cas, il est également possible de lancer un autre constructeur à partir d’un constructeur. Par exemple:
Java:
public class Personne {
protected String nom;
protected int age;
public Personne(String aNom, int aAge) {
nom = aNom;
age = aAge;
}
public Personne(String aNom) {
this(aNom, 0);
}
}
Eiffel:
class
PERSONNE
create
make,
make_with_nom
feature
nom: STRING
age: INTEGER
make (a_nom: STRING; a_age: INTEGER)
do
nom := a_nom
age := a_age
end
make_with_nom (a_nom: STRING)
do
make (a_nom, 0)
end
end
Les classes abstraites
Une classe abstraite permet la représentation d’une classe dont l’implémentation est incomplète. Une classe abstraite ne peut être instanciée.
Il est à noter que, même les classes abstraites doivent avoir un constructeur afin d’initialiser les attributs de cette classe.
Les méthodes abstraites
On dit qu’une méthode est abstraite si elle ne représente que la déclaration (signature) de la routine, et non son implémentation.
-
-
- Notez que seules des classes abstraites peuvent posséder des méthodes abstraites
- Sers généralement à permettre le polymorphisme
-
Héritage
Un lien d’héritage est un lien qui permet une généralisation/spécialisation d’une classe vers une autre. La classe plus spécifique possède tout ce que la classe générale possède, mais elle peut y ajouter de nouvelles méthodes, de nouveaux attributs ou de nouvelle implémentation (implémentation de méthode abstraite).
Par exemple, si on prend les classes Animal, Chien et Chat dans le diagramme suivant:
Il faut comprendre qu’un Animal est une généralisation de Chat et de Chien. Inversement, Chat et Chien sont des spécialisations d’Animal.
Parfois, on appelle les liens d’héritage des liens parent/enfant. Dans ce sens on appelle parents les généralisations directes et enfants, les spécialisations directes. Dans l’exemple précédent, Animal est un parent de Chat et Chien et ces derniers sont des enfants d’Animal.
Dans le même ordre d’idée, on appelle ancêtre les généralisations indirectes (plusieurs niveaux d’héritage) et descendant les spécialisations indirectes.
Il est à noter que, sauf exception, les constructeurs des classes enfants ont comme responsabilité de lancer les constructeurs des classes parents. Par exemple:
Java:
public class Etudiant extends Personne {
protected int numeroDA;
public Etudiant(String aNom, int aAge, int aNumeroDA) {
super(aNom, aAge);
numeroDA = aNumeroDA;
}
}
Eiffel:
class
ETUDIANT
inherit
PERSONNE
rename
make as make_personne
end
create
make
feature
numero_da: INTEGER
make (a_nom: STRING; a_age, a_numero_da: INTEGER)
do
make_personne (a_nom, a_age)
numero_da := a_numero_da
end
end
Le type d’un objet
Le type d’un objet représente la classe (ou le type primitif) utilisée dans la déclaration de la variable contenant cet objet. Par exemple, dans les codes suivants:
Java:
Chat mon_chat;
Eiffel:
mon_chat:CHAT
L’objet (et la variable) mon_chat est de type Chat.
Le type générateur
On appelle type générateur, la classe qui a permis d’instancier un objet. Par exemple, dans les codes suivants:
Java:
Animal mon_animal = new Chat();
Eiffel:
mon_animal:ANIMAL
mon_animal := create {CHAT}
Le type générateur de mon_animal est Chat.
Conformisme
On dit qu’un objet est conforme à un type si ce type est un ancêtre du type générateur de l’objet. Par exemple, dans les codes suivants:
Java:
Chat mon_chat = new Chat();
Eiffel:
mon_chat:CHAT
create mon_chat
On voit que le type générateur de mon_chat est la classe Chat. On peut donc dire que l’objet contenu dans mon_chat est conforme au type Animal puisque la classe Animal est un ancêtre de la classe Chat.
Les clients d’une classe
On dit qu’une classe A est client d’une classe B si un attribut ou une fonction de la classe A retourne un objet ou un ensemble d’objets de type B.
Il est à noter que, par simplicité, on élargit parfois cette définition afin d’y inclure tous les variables locales et arguments de méthodes.
Les fournisseurs d’une classe
On dit qu’une classe A est fournisseur d’une classe B si un attribut ou une fonction de la classe B retourne un objet ou un ensemble d’objets de type A. En d’autres mots, un lien fournisseur est l’inverse d’un lien client.
L’interface d’une classe
On appelle interface d’une classe, l’ensemble des méthodes et attributs accessibles à un client de cette classe.
Un petit truc
Pour savoir s’il est préférable de faire un lien d’héritage ou un lien client/fournisseur entre deux classes, on peut utiliser le petit truc suivant:
-
-
- Si on peut dire « est un » entre 2 classes, on a un lien d’héritage. Par exemple « Un chat est un animal ».
- Si on peut dire « a un » ou « a des » ou « utilise un » ou « utilise des » entre deux classes, on a un lien client/fournisseur. Par exemple, « Un client a des factures ».
-
Polymorphisme
Le polymorphisme est le fait de traiter de manière similaire plusieurs objets de types différents, avec une interface commune. Par exemple,
Dans ce diagramme, on voit que toutes les classes enfants de Moyen_de_transport ont la méthode bruit. On peut donc appeler la méthode bruit de tous ces objets sans avoir à se soucier de quelle classe il s’agit. Par exemple:
Java:
public void afficherBruits(List<MoyenDeTransport> aTransports) {
for (MoyenDeTransport laTransport : aTransports) {
laTransport.bruit();
}
}
Eiffel:
afficher_bruit(a_transports:LIST[MOYEN_DE_TRANSPORT])
do
across a_transports as la_transports loop
la_transports.item.bruit
end
end
Nous obtenons donc le résultat suivant:
Vroum Vroum Tchou Tchou Ding Ding Tchou Tchou Tchou Tchou Ding Ding Tchou Tchou Vroum Vroum Ding Ding Ding Ding Vroum Vroum
L’encapsulation
En général, l’interface d’une classe doit être séparée de son implémentation. En d’autres mots, le client d’une classe ne devrait pas pouvoir modifier les valeurs internes (variables et attributs d’implémentation) ni utiliser les méthodes d’implémentation de la classe.
Masquage de l’information
Les mécanismes de masquage de l’information permettent de mettre en oeuvre l’encapsulation d’une classe. La plupart des langages permettent les 3 mécanismes de masquage de l’information suivant:
-
-
- Méthode ou attribut privé: seule la classe en cours peut accéder à la méthode ou attribut;
- Méthode ou attribut protégé: seules la classe et les classes descendantes peuvent accéder à la méthode ou à l’attribut.
- Méthode ou attribut public: Toutes les classes peuvent accéder à la méthode ou à l’attribut.
-
Il est important de noter que ces 3 mécanismes peuvent varier en fonction des langages. Par exemple, le langage Python ne gère que des attributs et méthodes publiques.
public class MaClasse1 {
public int attribut1;
public String attribut2;
public int methode1() {
}
public String methode2() {
}
private int attribut3;
private String attribut4;
private int methode3() {
}
private String methode4() {
}
protected int attribut5;
protected String attribut6;
protected int methode5() {
}
protected String methode6() {
}
}
Dans l’exemple précédent, les attributs 1 et 2 ainsi que les méthodes 1 et 2 sont publics; les attributs 3 et 4 ainsi que les méthodes 3 et 4 sont privés; enfin les attributs 5 et 6 ainsi que les méthodes 5 et 6 sont protégés.
Masquage de l’information en Eiffel
Il y a deux notes à bien prendre en compte concernant Eiffel.
La première est qu’il n’y a pas de méthodes ou attributs « privé » dans Eiffel parce que ce mécanisme est en contradiction avec l’approche orientée objet. En effet, si un Chat est un Animal, donc Chat devrait avoir accès aux mêmes choses que Animal. Si ce n’est pas le cas, on ne peut pas dire qu’un Chat est un Animal. Dans des langages comme Java, on utilise les méthodes et attributs privés afin de s’assurer que les descendants de la classe ne rendent pas instable l’objet en modifiant d’une mauvaise manière les attributs et méthodes d’implémentation de la classe. Pour s’assurer que le problème n’arrive pas, Eiffel permet un mécanisme de contrat appelé « invariant » qui permet d’établir les règles qui doivent toujours être respectées dans la classe (autant pour la classe elle-même que pour les descendants; ce qui respecte le principe objet).
La seconde note à prendre en note pour le langage Eiffel, c’est que ce dernier permet plus de contrôle au niveau des contrôles d’interface en permettant une gestion de classes amies. Une classe amie est une classe ayant accès à une interface plus large que l’interface publique standard de la classe. Par exemple, une classe Liste_liée pourrait être la seule classe à avoir accès aux constructeurs de la classe Noeud_de_liste_liéé.
class
MA_CLASSE1
feature -- Accès
attribut1:INTEGER
attribut2:STRING
methode1
do
end
methode2
do
end
feature {NONE} -- Implementation
attribut3:INTEGER
attribut4:STRING
methode3
do
end
methode4
do
end
feature {MA_CLASSE2, MA_CLASSE3} -- Amis
attribut5:INTEGER
attribut6:STRING
methode5
do
end
methode6
do
end
end
Dans le code précédent, les attributs 1 et 2 ainsi que les méthodes 1 et 2 sont publics; les attributs 3 et 4 ainsi que les méthodes 3 et 4 sont protégés; enfin les attributs 5 et 6 ainsi que les méthodes 5 et 6 sont seulement accessibles à partir des classes MA_CLASSE5 et MA_CLASSE6.
Auteur: Louis Marchand
Sauf pour les sections spécifiées autrement, ce travail est sous licence Creative Commons Attribution 4.0 International.