Vous êtes sur la page 1sur 36

Dan Garlasu, dgarlasu@yahoo.

com

1
Ordre du jour
1. Réutiliser les classes
2. Classes abstraites
3. Interfaces
4. Polymorphisme

2
 La réutilisation du code est l'un des plus grands
avantages des langages de programmation orientés objet
 Il existe deux possibilités pour réutiliser des classes dans
des programmes orientés objet :
1. Réutilisation de l'implémentation – on compose une
nouvelle classe à partir des classes déjà existantes ->
création d'une classe composite
2. Réutilisation de l'interface - nous créons une sous-classe de
cette classe. La sous-classe hérite des fonctionnalités
(méthodes) de la superclasse

Une fois qu'une classe a été créée et testée, elle devrait (idéalement) représenter une
unité de code utile. S'il arrive qu'une telle classe ait une bonne conception et soit utile,
nous pourrions vouloir réutiliser cette classe. La réutilisation du code est l'un des plus
grands avantages des langages de programmation orientés objet.
Il existe deux possibilités pour réutiliser des classes dans des programmes orientés
objet :
• Réutiliser la mise en œuvre (composition)
• Réutilisation de l'interface (héritage)

3
 La façon la plus simple de réutiliser une classe dans une nouvelle classe est
de placer un objet de cette classe dans la nouvelle classe.
 Parce que nous composons une nouvelle classe à partir de classes
existantes, ce concept est appelé Composition (agrégation).
 La composition s'accompagne d'une grande flexibilité. Les objets membres
de la nouvelle classe sont généralement privés, ce qui les rend inaccessibles
aux programmeurs clients qui utilisent la classe.
 Cela permet aux programmeurs de modifier ces membres sans perturber le
code client existant.
 Ils peuvent également modifier les objets membres au moment de
l'exécution, pour modifier dynamiquement le comportement des objets
composés.
◦ La composition est souvent appelée relation "avoir-un", comme dans "une voiture a un moteur".

La composition est souvent appelée relation "a-un", comme dans "une voiture a un
moteur".

4
Example: public class Point{
private int x_;
 Pour créer une définition de classe pour des objets de private int y_;
forme 2D simples public Point(){
 Par exemple, la classe Point pourrait ressembler à ceci: }
public Point(int x, int y){
Chaque objet de type forme a une couleur, une position x_ = x;
où il est placé sur l'écran, une dimension (largeur et y_ = y;
hauteur), etc. Maintenant, supposons que nous ayons }
déjà des classes qui représentent des objets de couleur, public int getX(){
return x_;
des objets de point et des objets de dimension.
}
Supposons que, de la même manière, la classe Color et public int getY(){
la classe Dimension aient été définies et qu'elles return y_;
encapsulent respectivement les valeurs RGB (Red }
Green Blue) et les valeurs de largeur et de hauteur. En public void setX(int x){
outre, ils fournissent un certain nombre de méthodes x_ = x;
pour manipuler les données encapsulées, ainsi que des }
constructeurs pour une initialisation paramétrée des public void setY(int y){
y_ = y;
objets.
}
}

Chaque objet forme a une couleur, une position où il est placé sur l'écran, une
dimension (largeur et hauteur), etc. Maintenant, supposons que nous ayons déjà des
classes qui représentent des objets de couleur, des objets de point et des objets de
dimension.
Supposons que, de la même manière, la classe Color et la classe Dimension aient
été définies et qu'elles encapsulent respectivement les valeurs RGB (Red Green Blue)
et les valeurs de largeur et de hauteur. En outre, ils fournissent un certain nombre de
méthodes pour manipuler les données encapsulées, ainsi que des constructeurs pour
une initialisation paramétrée des objets.

5
 Nous pouvons maintenant composer la classe Shape à partir des classes Color, Point et Dimension:
public class Shape{ // …
private Color color_; public Rectangle getBounds(){
private Point position_; return new Rectangle(position_.getX(),
private Dimension dim_; position_.getY(),
public Shape(){ dim_.getWidth(),
} dim_.getHeight());
public Shape(Point position, Dimension dim){
}
this(position, dim, new Color(0, 0, 0));
}
public void setBounds(Rectangle bounds){
public Shape(Point position, Dimension dim, Color color){ position_.setX(bounds.getX());
position_ = position; position_.setY(bounds.getY());
dim_ = dim; dim_.setWidth(bounds.getWidth());
color_ = color dim_.setHeight(bounds.getHeight());
} }
// here comes some code }

Dans les deux méthodes, imprimées en caractères gras dans le code ci-dessus, nous voyons un exemple de fournir la
classe Shape d'une certaine fonctionnalité (obtention et définition des limites) en réutilisant la fonctionnalité, qui est déjà
fournie par les classes Point et Dimension.
Une autre chose intéressante à remarquer dans l'exemple ci-dessus est la façon dont nous avons imbriqué les appels
de constructeur. Le deuxième constructeur, qui prend un objet Point et un objet Dimension, appelle le troisième
constructeur, qui prend un objet Point, une Dimension et un objet Color. Ceci est réalisé en utilisant l'auto-référence
d'un objet: this.

Dans les deux méthodes, imprimées en caractères gras dans le code ci-dessus, nous
voyons un exemple de fournir la classe Shape d'une certaine fonctionnalité (obtention
et définition des limites) en réutilisant la fonctionnalité, qui est déjà fournie par les
classes Point et Dimension.
Une autre chose intéressante à remarquer dans l'exemple ci-dessus est la façon dont
nous avons imbriqué les appels de constructeur. Le deuxième constructeur, qui prend
un objet Point et un objet Dimension, appelle le troisième constructeur, qui prend un
objet Point, une Dimension et un objet Color. Ceci est réalisé en utilisant l'auto-
référence d'un objet: this.

6
 En résumé, la composition s'accompagne d'une
grande flexibilité :
◦ Les objets membres de la nouvelle classe sont
généralement privés, ce qui les rend inaccessibles aux
programmeurs clients qui utilisent la classe
◦ Cela permet aux programmeurs de modifier ces membres
sans perturber le code client existant
◦ Ils peuvent également modifier les objets membres au
moment de l'exécution, pour modifier dynamiquement le
comportement des objets composés

7
 L'autre façon de réutiliser un code de classe peut être obtenue par héritage
 L'héritage permet aux programmeurs de définir une classe comme une sous-
classe d'une classe existante. La sous-classe hérite ainsi de toutes les
variables d'instance et de toutes les méthodes de la classe de base, tant
qu'elles ont été déclarées publiques ou protégées
 Le niveau d'héritage peut être arbitrairement profond
◦ Cela signifie que nous pouvons créer une sous-classe à partir d'une classe qui est déjà
une sous-classe d'une autre classe.
◦ Si nous avons plus d'un niveau d'héritage, alors une sous-classe hérite des variables et
des méthodes de tous les ancêtres de sa super-classe
 En Java, le concept d'héritage s'appelle l'extension d'une classe
◦ le mot-clé extend déclare qu'une classe est une sous-classe d'une autre classe

8
 Nous utilisons à nouveau le même exemple de la section précédente. Supposons que nous
ayons la classe Shape représentant des formes 2D que nous pouvons dessiner sur l'écran:
public class Shape{ public void draw(Graphics g){
protected Color color_; // here comes implementation
protected Point position_; }
protected Dimension dim_; public void erase(){
public Shape(){ // here comes implementation
}
}
public Rectangle getBounds(){
public Shape(Point position, Dimension dim){ return new Rectangle(position_.getX(),
this(position, dim, new Color(0, 0, 0)); position_.getY(),
dim_.getWidth(), dim_.getHeight());
} }
public Shape(Point position, Dimension dim, Color color){ public void setBounds(Rectangle bounds){
position_ = position; position_.setX(bounds.getX());
dim_ = dim; position_.setY(bounds.getY());
color_ = color dim_.setWidth(bounds.getWidth());
} dim_.setHeight(bounds.getHeight());
}
}

Dans la section précédente, nous avons présenté cette classe pour démontrer le principe de composition. Ici on furnise le code
complet de la classe Shape. Notez que le code inclut désormais des méthodes qui reflètent un comportement typique que
nous attendrions de la classe Shape. Ainsi, nous avons des méthodes que nous pouvons appeler pour dessiner une forme ou
effacer une forme, par exemple.

Évidemment, la classe Shape que nous avons introduite représente très bien les
choses que toutes les formes ont en commun, mais nous avons besoin de classes plus
spécialisées afin de représenter différentes formes. Ces sous-classes étendent la
classe Shape et ajoutèrent les variables d'instance requises pour implémenter un
comportement différent et plus spécialisé. Ainsi, la classe Circle dessinerait un cercle
sur un écran utilisateur et la classe Triangle dessinerait un triangle
Notez également que nous avons changé les modificateurs d'accès pour les variables
d'instance de la classe Shape de private à protected... Pourquoi ? … Nous l'avons
fait parce que nous voulons que les sous-classes de la classe Shape obtiennent
l'accès à ses variables d'instance.

9
 Regardons maintenant un exemple pour la classe
Circle:

public class Circle extends Shape{


public void draw(Graphics g){
// here comes the Circle specific code
}
}

Tout d'abord, nous remarquons le mot-clé extend, qui déclare qu'une classe est une sous-classe
d'une autre classe. Ensuite, nous voyons que la classe Circle remplace (implémente d'une autre
manière) la méthode draw de la classe Shape de base, afin d'implémenter un comportement
spécifique pour l'objet Circle.

11
 Regardons maintenant un autre exemple:

public class Polygon extends Shape{


private Point[] points_;
public Polygon(Point[] points){
points_ = points;
}
public void draw(Graphics g){
// here comes the Polygon specific code
}
}

Notez que la classe Polygon remplace non seulement la méthode draw, mais ajoute également une
nouvelle variable d'instance spécifique à la classe Polygon. C'est un tableau de points qui
représentent les points de ce polygone.

12
 La capacité d'une sous-classe à remplacer une méthode dans sa
superclasse permet à une classe d'hériter d'une superclasse dont
le comportement est "suffisamment proche", afin de remplacer les
méthodes selon les besoins
 Nous l'avons déjà vu sur les exemples des classes Circle et
Polygon qui substituent la méthode draw de la classe DE base
Shape.
 Ainsi, on voit que ces deux classes fournissent des
implémentations différentes pour la méthode draw et donc un
comportement différent pour les deux classes.

13
 Regardons de plus près ces deux méthodes substituées:
public class Polygon extends Shape{
public void draw(Graphics g){
g.setColor(color_);
for(int i = 0; i < (points_.length – 1); i++)
g.drawLine(points_[i].getX(), points[i].getY(),
points_[i+1].getX(), points_[i+1].getY());
}
// here is other code
}
public class Circle extends Shape{
public void draw(Graphics g){
g.setColor(color_);
g.drawOval(position_.getX(), position_.getY(),
dim_.getWidth(), dim_.getHeight());
}
}

Encore une fois, on voit que ces deux classes fournissent des implémentations
différentes pour la méthode draw et donc un comportement différent pour les deux
classes.
Une autre chose importante à noter est que le type de retour, le nom de la méthode, le
nombre et le type des paramètres de la méthode de remplacement doivent
correspondre à ceux de la méthode remplacée.

14
 Un autre aspect important du mécanisme d'héritage est l'initialisation des
objets d'une sous-classe
 Fondamentalement, un objet d'une sous-classe est une instance des
deux classes : sous-classe et super-classe. Ainsi, une initialisation
correcte des deux "objets" doit être accomplie
 En Java, le constructeur défaut vide d'une classe (default empty
constructor) est automatiquement appelé lors de la création d'un objet.
Dans la situation q’une classe est une sous-classe d'une autre classe, le
système Java appelle automatiquement en premier instance le
constructeur de la superclasse
 Dans le cas où le programmeur veut définir des constructeurs qui
prennent des arguments, alors il doit appeler le constructeur de la
superclasse par lui-même

15
 Regardons l'exemple suivant pour le démontrer:

public class Polygon extends Shape{


private Point[] points_;
public Polygon(Point[] points, Point position,
Dimension dim){
super(position, dim);
points_ = points;
}
// ici, on continue avec le reste
}

Le code en gras caractères appelle le constructeur de la superclasse pour initialiser correctement ses
variables d'instance. Cet appel doit être la première chose qu'un constructeur de sous-classe exécute

16
 Parfois, nous voulons créer des classes plus complexes qui combinent
éventuellement les mécanismes de composition et d'héritage.
 Supposons que nous voulions avoir un objet Shape composite, qui regroupe
un certain nombre d'autres formes. Nous pouvons traiter tous les objets
Shape qui sont placés dans l'objet groupé comme un seul objet Shape.
 Un tel objet est un objet de forme spécial, c'est-à-dire qu'il peut être
représenté par une sous-classe de la classe Shape et en même temps c'est
un objet composite qui contient, par exemple, un tableau d'autres objets de
forme.
 Les mots clés
◦ extend and
◦ private
qui représentent les mécanismes d'héritage et de composition

17
 Le code d'une telle classe Group pourrait ressembler à ceci:

public class Group extends Shape{


private Shape[] shapes_;
public Group(Shape[] shapes){
shapes_ = shapes;
}
public void draw(Graphics g){
for(int i = 0; i < shapes_.length; i++)
shapes_[i].draw(g);
}
}

Le code en caractères gras de l'exemple ci-dessus représente les mécanismes d'héritage et de


composition

18
 Parfois, une classe que nous définissons représente un concept abstrait et,
en tant que tel, ne doit pas être instancié.
 Au contraire, il devrait simplement servir de superclasse de base pour un
certain nombre de classes plus spécialisées.
 Cela signifie qu'une classe abstraite de base définit simplement une interface
qui doit être partagée entre ses sous-classes.
 Étendre une classe abstraite revient à étendre une classe normale.
◦ La seule différence est qu'une sous-classe pour devenir une classe normale, c'est-à-dire
une classe à partir de laquelle nous pouvons créer des instances, doit implémenter toutes
les méthodes abstraites de sa super-classe abstraite. Sinon, cette sous-classe est
également considérée comme une classe abstraite et il n'est donc pas possible de créer
ses instances.

Si nous y réfléchissons davantage, nous pouvons conclure qu'il n'est pas nécessaire
de créer des instances de la classe Shape, car une instance d'une classe Shape qui
n'est pas également une instance d'une sous-classe spéciale n'est pas très utile, car
une telle instance Shape ne sait pas comment se dessiner, par exemple. Il sait qu'il
s'agit d'une forme, mais il ne sait pas de quelle forme il s'agit.
Évidemment, nous pourrions et devrions (pour empêcher la création d'objets qui ne
savent pas se dessiner eux-mêmes, par exemple) définir la classe Shape comme une
classe abstraite. Techniquement, définir une classe abstraite signifie que nous
définissons un certain nombre de ses méthodes comme étant abstraites, c'est-à-dire
que nous ne leur fournissons pas l'implémentation mais laissons plutôt les sous-
classes le faire. De toute évidence, la méthode draw et par exemple la méthode erase
des classes Shape doivent être définies de manière abstraite, car les classes spéciales
doivent implémenter elles-mêmes ce comportement spécial.

19
 Pour créer une classe abstraite, nous devons la déclarer abstraite et en plus de cela, nous
devons déclarer un certain nombre de ses méthodes comme étant abstraites. Revoyons la
classe Shape d'en haut et définissons-la comme une classe abstraite:
abstract public class Shape{ abstract public void draw(Graphics g);
protected Color color_; abstract public void erase();
protected Point position_; public Rectangle getBounds(){
protected Dimension dim_; return new
public Shape(){ Rectangle(position_.getX(),
} position_.getY(),
public Shape(Point position, Dimension dim){ dim_.getWidth(),
this(position, dim, new Color(0, 0, 0)); dim_.getHeight());
}
} public void setBounds(Rectangle
public Shape(Point position, Dimension dim, Color bounds){
color){ position_.setX(bounds.getX());
position_ = position; position_.setY(bounds.getY());
dim_ = dim; dim_.setWidth(bounds.getWidth());
color_ = color dim_.setHeight(bounds.getHeight());
} }
}

Notez le code en caractères gras déclarant que la classe Shape et deux de ses
méthodes sont abstraites.

21
 Pensez à une classe abstraite dont toutes les méthodes sont déclarées
abstraites. De toute évidence, une telle classe abstraite ne fournit qu'une
interface pour toutes ses sous-classes.
 En Java ce concept a obtenu un mot-clé spécial: interface
 Une interface définit un protocole de comportement qui peut être
implémenté par n'importe quelle classe n'importe où, dans la hiérarchie des
classes.
 Une interface définit un ensemble de méthodes mais ne les implémente pas.
 Une classe qui implémente l'interface s'engage à implémenter toutes les
méthodes définies dans l'interface, acceptant ainsi un certain comportement.
Cette classe obtient également le type de cette interface.
 La diapo suivante montre la différence entre une classe abstraite et une
interface

Parlons maintenant de la différence entre une classe abstraite et une interface

22
Question:
 Par-ce qu'une interface est simplement une liste de méthodes non
implémentées, et donc abstraites, quelle est la différence entre une
interface et une classe abstraite?
◦ Une interface ne peut implémenter aucune méthode, contrairement à une classe
abstraite.
◦ Une classe peut implémenter de nombreuses interfaces mais ne peut avoir
qu'une seule superclasse.
◦ Une interface ne fait pas partie de la hiérarchie des classes. Des classes non
liées peuvent implémenter la même interface
 Les différences sont importantes!

23
 Nous avons déjà vu comment nous pouvons utiliser des
collections pour stocker des objets de différents types.
 Nous avons également introduit le concept d'itérateur, qui est
un objet que nous utilisons pour parcourir les objets d'une
collection particulière.
 L'objet iterator est un exemple typique d'utilisation d'une
interface au lieu d'une classe.

24
 Fondamentalement, un objet itérateur nous permet d'aller et venir, par
exemple, entre les membres d'une collection. Ces membres sont stockés
dans cette collection, mais un itérateur accepte simplement de traverser le
comportement. Il ne contient pas les objets de cette collection. Nous
pourrions définir une interface d'itérateur comme celle-ci:

public interface Iterator{


public Object next();
public boolean hasNext();
}
 Remarquez le mot-clé interface en gras. Nous voyons également dans
l'exemple ci-dessus qu'une interface déclare simplement un certain nombre
de méthodes de la même manière qu'une classe abstraite. La différence ici
est que nous n'avons pas besoin d'utiliser le mot-clé abstract pour le faire

25
 Si une classe choisit d'étendre une interface, nous disons que
cette classe implémente cette interface.
 Le principe ici est le même que pour les classes abstraites. Si
une classe implémente une interface, elle doit implémenter
toutes ses méthodes afin de ne pas être une classe abstraite.
 Sinon, la classe est considérée comme une classe abstraite et
nous ne pouvons donc pas créer d'instances de cette classe

26
 Regardons un exemple de classe qui implémente l'interface Iterator d'en
haut:
public class ArrayList implements Iterator{
private int cursor_;
public boolean hasNext(){
return (cursor_ != size());
}
public Object next(){
return get(cursor_++);
}
public Iterator iterator(){
cursor_ = 0;
return this;
}
// other code comes here
}

Dans l'exemple ci-dessus, la classe ArrayList implémente l'interface Iterator. La classe ArrayList
implémente toutes les méthodes déclarées dans l'interface Iterator, donc cette classe n'est pas une
classe abstraite et nous pouvons créer ses instances.

27
 Il y a plusieurs problèmes importants de l'exemple ci-dessus que
nous devons mentionner ici:
◦ La classe ArrayList implémente elle-même l'interface Iterator, donc l'itérateur
de méthode renvoie cette référence, c'est-à-dire la référence de l'objet
ArrayList lui-même. Rappelez-vous qu'une classe implémentant une interface
a aussi le type de cette interface.
◦ Étant donné que la classe ArrayList implémente l'interface Iterator, les
méthodes qui remplacent cette interface peuvent appeler directement d'autres
méthodes de ArrayList. Par exemple, la méthode appelle ensuite la méthode
get de la classe ArrayList.
◦ Une autre classe pourrait être créée, par exemple ArrayListIterator, qui
pourrait être une classe distincte implémentant uniquement l'interface Iterator.
Dans ce cas, la méthode Iterator de la classe ArrayList créerait une instance
distincte de la classe ArrayListIterator et retournait cette instance

28
 Comme nous l'avons mentionné précédemment, une classe peut étendre
une autre classe afin de spécialiser ses caractéristiques et son
comportement.
 Dans certains langages orientés objet, une classe peut étendre non
seulement une classe mais également un certain nombre d'autres classes.
C'est ce qu'on appelle l'héritage multiple
 Il y a plusieurs problèmes avec ce concept :
◦ il n'y a pas de prise en charge de l'héritage multiple pur en Java. Cela signifie qu'en Java,
une classe ne peut étendre qu'une seule superclasse.
◦ Cependant, cela peut être trop restrictif dans certains cas et Java prend donc en charge
"une sorte" d'héritage multiple
◦ Une classe en Java peut implémenter un certain nombre d'interfaces, elle "hérite" donc de
plusieurs sources. Étant donné que les interfaces ne sont que des déclarations de
méthodes et qu'il n'y a pas d'implémentation définie par les interfaces, le problème que
nous avons décrit précédemment n'existe pas en Java.

29
 Un mécanisme très important dans les langages orientés objet.
 Nous appelons dans notre code la méthode d'une instance d'une classe
de base, mais au moment de l'exécution, le système appelle la bonne
méthode de chaque objet particulier, c'est-à-dire:
◦ s'il rencontre un objet cercle, il appelle la méthode draw de cet objet cercle;
◦ s'il rencontre un objet polygone, il appelle la méthode draw de l'objet polygone, etc.
Comme effet de cette forme, les objets sont dessinés de la manière dont nous nous
attendons à ce qu'ils soient dessinés.
 Techniquement, en raison du polymorphisme, les objets sont
interchangeables ou substituables dans les programmes orientés objet.
◦ Cela signifie que nous pouvons écrire du code qui parle aux formes et gérer
automatiquement tout ce qui correspond à la description d'une forme, c'est-à-dire, par
exemple, gérer tout ce qui est une sous-classe de la classe Shape.

30
 Reprenons l'exemple de la classe de forme Group ci-dessus. Justement,
étudions plus en détail sa méthode de tirage:

public class Group extends Shape{ public void draw(Graphics g){


for(int i = 0; i < shapes_.length; i++)
shapes_[i].draw(g);
}
// …
}
 Une instance de la classe Group contient un tableau d'instances d'autres classes Shape,
telles que des cercles, des polygones, des triangles, etc. La méthode draw de la classe
Group parcourt toutes les formes, et les dessine une par une, sur l'écran de l'utilisateur. Les
lignes du code en caractères gras ci-dessus montrent l'invocation de la méthode draw de
chaque objet Shape particulier

31
Examinons maintenant comment les langages de programmation orientés objet
implémentent le polymorphisme.
 Dans les langages de programmation traditionnels, par ex. dans les langages de
programmation procéduraux tels que C, le compilateur effectue un appel de fonction de
manière statique.
 Cela signifie que le compilateur génère un appel à un nom de fonction spécifique et que
l'éditeur de liens résout cet appel à l'adresse absolue du code à exécuter.
 Ce principe est appelé liaison statique ou liaison anticipée d'un appel de fonction.

 La liaison statique signifie que dans le cas de l'exemple Shape ci-dessus, le compilateur
lierait l'appel à la méthode draw de la classe Shape au moment de la compilation, donc,
au moment de l'exécution, la méthode draw de la classe Shape de base serait appelée
pour chaque objet de forme particulière quel que soit son type réel.
Désavantage: La liaison statique ne peut pas être appliquée si nous voulons prendre en
charge le polymorphisme.

32
 Par conséquent, les langages orientés objet prennent en charge un autre
type d'appels de fonction de liaison - liaison dynamique ou liaison tardive.
 La liaison dynamique signifie que lorsque vous envoyez un message à un
objet, le code appelé n'est déterminé qu'au moment de l'exécution. Le
compilateur s'assure que la fonction existe et effectue une vérification de
type sur les arguments et la valeur de retour, mais il ne connaît pas le code
exact à exécuter.
 Pour effectuer une liaison tardive, Java utilise un morceau de code spécial
au lieu de l'appel absolu. Ce code calcule l'adresse du corps de la fonction,
en utilisant les informations stockées dans l'objet. Ainsi, chaque objet peut
se comporter différemment selon le contenu de ce morceau de code
spécial. Lorsque vous envoyez un message à un objet, l'objet détermine
réellement quoi faire avec ce message.

33
 Le polymorphisme nous permet d'échanger (substituer) un objet de type A
pour un objet de type B, où le type A est une sous-classe du type B (peu
importe à quel niveau d'héritage)
 Reprenons l'exemple de Shape:
Shape[] shapes = new Shape[2];
shapes[0] = new Circle(new Point(100, 100), 50);
shapes[1] = new Polygon(new Point(0, 0), 100, 50);
Group group = new Group(shapes);
 Tout d'abord, nous remarquons que nous substituons un cercle et un objet
polygone aux objets de sa classe Shape de base (par exemple, shapes[0] et
shapes[1]). Nous traitons les instances de classes héritées comme des
instances d'une classe de base.

34
 Le transtypage ascendant consiste à traiter un type dérivé
comme s'il s'agissait de son type de base. Le nom
transtypage (cast) est utilisé dans le sens de couler dans un
moule et le haut (up) vient de la façon dont le diagramme
d'héritage est généralement organisé, avec le type de base
en haut et les classes dérivées en éventail vers le bas. Ainsi,
le transtypage vers un type de base remonte le diagramme
d'héritage : "upcasting".

35
 Le polymorphisme permet aux programmes orientés objet
d'être facilement extensibles. Imaginez que nous écrivions le
code d'une autre classe Shape, disons la classe Ellipse. Il
est clair que nous n'avons pas besoin de modifier le code de
la classe Group pour inclure des objets ellipse dans de
nouveaux objets Group. Puisque la classe Ellipse est une
sous-classe de la classe Shape, tout s'adapte parfaitement.
Peu importe que nous ayons créé la classe Ellipse en plus.

36
 Les langages orientés objet ont leur juste part d'excellentes applications:
◦ Le développement de logiciels,
◦ Le développement de jeux et la programmation graphique
sont exemples où la programmation orientée objet est une excellente approche à adopter.
 Voici une liste d'exemples de langages appartenant au paradigme orienté
objet:
 C++
 Java
 JavaScript
 Python
 Scala

37
 Le cours sera délivré en ligne
 Sur Microsoft Teams
 Même heure

38

Vous aimerez peut-être aussi