0% ont trouvé ce document utile (0 vote)
22 vues65 pages

C01 2 Substitution

Le document traite de la programmation orientée objet en Java, en se concentrant sur la substitution et l'héritage. Il présente des exemples de code en Python et Java pour illustrer les concepts de classe, sous-classe et méthodes associées. Enfin, il aborde des considérations sur l'utilisation des règles conditionnelles dans les langages de programmation, en soulignant l'importance de la simplicité dans le code.

Transféré par

Hanyny Mohamed
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
22 vues65 pages

C01 2 Substitution

Le document traite de la programmation orientée objet en Java, en se concentrant sur la substitution et l'héritage. Il présente des exemples de code en Python et Java pour illustrer les concepts de classe, sous-classe et méthodes associées. Enfin, il aborde des considérations sur l'utilisation des règles conditionnelles dans les langages de programmation, en soulignant l'importance de la simplicité dans le code.

Transféré par

Hanyny Mohamed
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Programmation Orientée Objet - Java

C01.2 : Substitution

Génie Informatique Industrielle

• Introduction sur ce qu'il faut oublier à propos de l'héritage ...


• Programmation par règles
• Factorisation de code
• Délégation et substitution
• Conclusion sur les deux (seuls) schémas à retenir ...

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 1/65


L'héritage est un sous-typage, c-à-d la spécialisation (restriction)
d'une classe par extension fonctionnelle

MyClass
Classe mère
anOperation()

relation estUn

Classes filles MySubClassA MySubClassB


anotherOpForA() anOperation()
anotherOpForB()

MySubClassC
anOperation()
anotherOpForC()

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 2/65


Exemple : un carré est un rectangle les 4 cotés ont même mesure

Rectangle
Longueur
largeur

Carre
cote

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 3/65


Rectangle
L'exemple en code Python, en style pythonesque Longueur
largeur

Carre
cote
• ...
class Rectangle:
def __init__(self, longueur=30, largeur=15): #Initialisateur
self.L, self.l = longueur, largeur
self.nom = ”rectangle”
def __str__(self): # toString()
return ”nom : {}”.format(self.nom)
...
class Carre(Rectangle): # héritage simple
”””Sous-classe spécialisée de la super-classe Rectangle.”””
def __init__(self, cote=20): #Initialisateur
# appel au constructeur de la super-classe de Carre :
super().__init__(cote, cote)
self.nom = ”carré” # surcharge d’attribut
...

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 4/65


Exemple similaire en style Java : classe Rectangle, fabrication

public class Rectangle { //Rectangle Attributes


//Constants protected Double lenght = Rectangle.LENGHT_DEFAULT_VALUE;
//Default values protected Double width = Rectangle.WIDTH_DEFAULT_VALUE;
private static final double LENGHT_DEFAULT_VALUE = 30.0d; protected String name = Rectangle.DEFAULT_NAME;
private static final double WIDTH_DEFAULT_VALUE = 15.0d;
private static final String DEFAULT_NAME = "Rectangle"; //Constructor
//The values of length and width are conformed!!!
//Factory Method protected Rectangle(Double length, Double width) {
public static Rectangle getInstance(Double length, Double width) { this.lenght = length;
//Check for domain values this.width = width;
if (length <= 0.0) { }
System.out.println("getInstance(Double length= "+length+",
Double width= "+width+"), length is negative or null ==> return
null!");
return null;
}
if (width <= 0.0) {
System.out.println("getInstance(Double length= "+length+",
Double width= "+width+"), width is negative or null ==> return null!");
return null;
}
//All is ok ==> Build an instance
Rectangle aRectangle = new Rectangle(length, width);
return aRectangle;
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 5/65


Exemple similaire en style Java : classe Rectangle, getters et
setters

//Getters and Setters public String getName() {


public Double getLenght() { return this.name;
return this.lenght; }
} public int setName(String name){
public int setLenght(Double length) { //Check for the definition domain
//Check for the definition domain if(name == null){
if (length <= 0) { System.out.println("setName(String name= null), name is
null ==> Do noting and return -1!");
System.out.println("setLenght(Double length=
"+length+")length is negative or null ==> Do noting and return -1!"); return -1;
return -1; }
} if(name.isEmpty() == true){
//All is ok System.out.println("setName(String name= ), name is empty
==> Do noting and return -2!");
this.lenght = length;
return -2;
return 1;
}
}
//All is ok
public Double getWidth() {
this.name = name;
return this.width;
return 1;
}
}
public int setWidth(Double width) {
//Check for the definition domain
if (width <= 0) {
System.out.println("setWidth(Double width= "+ width + "),
width is negative or null ==> Do noting and return -1!");
return -1;
}
//All is ok
this.width = width;
return 1;
}
©Marc LE GOC 2025 - Programmation Orientée Objet - Java 6/65
Exemple similaire en style Java : et finalement, les sections
toString et equals de la classe Rectangle

//toString section //equals section


@Override @Override
public String toString() { public boolean equals(Object anObject) {
StringBuilder aStringBuilder = new StringBuilder(); //Check for the domain definition
if (anObject == null) {
aStringBuilder.append(Rectangle.DEFAULT_NAME); return false;
aStringBuilder.append(": "); }
aStringBuilder.append("name is "); //Check for the class
aStringBuilder.append(this.name); if (this.getClass() != anObject.getClass()) {
aStringBuilder.append(", lenght="); return false;
aStringBuilder.append(this.lenght); }
aStringBuilder.append(", width="); //Instances of the same class
aStringBuilder.append(this.width); final Rectangle anotherRectangle = (Rectangle) anObject;
aStringBuilder.append("."); //1°) Check for the name
if (this.name.equalsIgnoreCase(anotherRectangle.getName()) ==
false) {
return aStringBuilder.toString();
return false;
}
}
//2°) Same name ==> Check for the lenght and the width
if (this.lenght.equals(anotherRectangle.getLenght()) == false)
{
return false;
}
return (this.width.equals(anotherRectangle.getWidth()));
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 7/65


Exemple similaire en style Java : classe Carre, fabrication, getters
et setters

• public final class Carre extends Rectangle{ • //Getters and Setters


• //Constant • public Double getSide() {
• private final String DEFAULT_NAME = "Carre"; • return this.lenght;
• • }
• //Factory Method •
• public static Carre getInstance(Double side) { • public int setSide(Double length) {
• //Check for domain values • //Check for the definition domain
• if (side <= 0.0) { • if (length <= 0) {
• System.out.println("getInstance(Double side= • System.out.println("setLenght(Double length=
"+side+"), side is negative or null ==> return null!"); "+length+")length is negative or null ==> Do noting and
return -1!");
• return null;
• return -1;
• }
• }
• //All is ok ==> Build an instance
• //All is ok
• Carre aRectangle = new Carre(side);
• this.side = length;
• return aRectangle;
• return 1;
• }
• }


• //Constructor
• private Carre(Double side) {
• super(side, side);
• this.name = DEFAULT_NAME;
• }

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 8/65


Exemple similaire en style Java : et finalement, les sections
toString et equals de la classe « Carre »

• //toString section • //equals section


• @Override • @Override
• public String toString() { • public boolean equals(Object anObject) {
• StringBuilder aStringBuilder = new • //Check for the domain definition
StringBuilder();
• if (anObject == null) {

• return false;
• aStringBuilder.append(DEFAULT_NAME);
• }
• aStringBuilder.append(": ");
• //Check for the class
• aStringBuilder.append("name is ");
• if (this.getClass() != anObject.getClass()) {
• aStringBuilder.append(this.name);
• return false;
• aStringBuilder.append(", lenght=");
• }
• aStringBuilder.append(this.lenght);
• //Instances of the same class
• aStringBuilder.append(", width=");
• final Carre anotherCarre = (Carre) anObject;
• aStringBuilder.append(this.width);
• //1°) Check for the name
• aStringBuilder.append(".");
• if
• (this.name.equalsIgnoreCase(anotherCarre.getName()) ==
false) {
• return aStringBuilder.toString();
• return false;
• }
• }

• //2°) Same name ==> Check for the side
• return
(this.lenght.equals(anotherCarre.getWidth()));
• }

• }

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 9/65


Premier constat : Java est beaucoup, beaucoup plus bavard que
Python !

• Certes mais attention : ces deux codes ne sont pas du tout équivalents !
• Le code Python est pythonesque ... c'est à dire malsain !
• Rien n'étant controlé, on peut créer des rectangles avec des longueurs négatives (cela
est certes possible mais pas en géométrie euclidienne !)
• L'utilisateur est fortement responsabilisé : de là le fameux slogan des développeurs
Python « We’re all consenting adults here » (nous sommes entre adultes consentants).
• Le code Java est sain
• Les domaines de définition des fonctions de mesure sont systématiquement vérifiés
• L'utilisateur a moins de responsabilité
• Il est possible d'écrire un code Python aussi sain que celui de Java : il sera alors beaucoup moins
pythonesque et beaucoup plus long !
• Même s'il restera légèrement plus court que son équivalent Java

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 10/65


Programmation Orientée Objet - Java

C01.2 : Substitution

Génie Informatique Industrielle

• Introduction sur ce qu'il faut oublier à propos de l'héritage ...


• Programmation par règles
• Factorisation de code
• Délégation et substitution
• Conclusion sur les deux (seuls) schémas à retenir ...

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 11/65


Remarque : tous les langages informatiques propose une syntaxe
pour coder une implication logique (⇒)

• En mathématique, on désigne sous le terme de fonction f : X →Y, y = f(x), l'expression


analytique d'un moyen de constituer l'ensemble des couples (xi, yi)∈X×Y tel que l'implication
suivante soit satisfaite :
• ∀xi∈X, (x = xi) ⇒ (∃yj∈Y, y = yj)
• La forme d'une formule basée sur une implication ⇒ est appelée « règle »
• Une règle s'utilise dans un raisonnement déductif appelé Modus Ponens (i.e. moyen
d'affirmer) :
• 1. x = xi
• 2. (x = xi) ⇒ (∃yj∈Y, y = yj)
• 3. y = yj (CQFD)
• Le Modus Ponens s'exprime en langue naturelle par « Si ... alors ... » :
• Si x = xi alors y = yj (sous-entendu « selon f »)

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 12/65


Des règles « Si ... alors ... » au règles « if ... then ... » des
langages informatiques

• Coder une fonction f : X →Y, y = f(x), consiste à coder une expression appelée règle « Si x = xi
alors y = yj » applicable à toutes valeurs xi du domaine de définition X de f :
• ∀xi, (xi∉X) ⇒ (∄ yj∈Y, y = yj)
• ∀xi∈X, (x = xi) ⇒ (∃yj∈Y, y = yj)
• Dans ce but, les langages informatiques ont introduit le test logique :
• if (xi∈X) then (∃yj∈Y, y = yj) else (∄ yj∈Y, y = yj)
• Cette forme est strictement équivalente aux deux règles Suivantes (KISS!) :
• Règle 1 : if (xi∉X) then (∄ yj∈Y, y = yj)
• Règle 2 : if (xi∈X) then (∃yj∈Y, y = yj)
• Le else des langages informatiques est donc a priori inutile
• En pratique, l’usage du else s'avère très dangereux parce qu'il masque la complexité
introduite par la négation d’un test logique

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 13/65


Remarque importante sur l'usage du if

• En Python, la syntaxe est celle d'un choix :


• if condition1:
# bloc exécuté si condition1 est vraie
• elif condition2:
# bloc exécuté si condition2 est vraie
• else:
# bloc exécuté si toutes conditions fausses
• L'équivalent Java est :
• if (condition1 == true) {
• //bloc exécuté si condition1 est vraie
• } else {
• if (condition2 == true) {
• //bloc exécuté si condition2 est vraie
• } else {
• //bloc exécuté si toutes conditions fausses
• }//Fin bloc else 2
• }//Fin bloc else 1

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 14/65


Remarque importante sur l'usage du if

• En Python, la syntaxe est celle d'un choix :


• if condition1:
# bloc exécuté si condition1 est vraie
• elif condition2:
# bloc exécuté si condition2 est vraie
• else: Ce code en Python comme celui
en Java sont
# bloc exécuté si toutes conditions fausses
épouvantables parce qu'horriblement compliqués et dangereux !
• L'équivalent Java est :
• if (condition1 == true) {

Le else ou//bloc
le elif exprimant implicitement la négation de la condition
exécuté si condition1 est vraie
• exprimée} par
elsele{ premier if, il est très facile de se tromper dès que cette
• condition contient
if (condition2 un « et
== true) { » ou un « ou » logique !
• //bloc exécuté si condition2 est vraie
• La philosophie KISS!,
} else { Keep It Simple, Stupid!, invite à ne programmer
• //blocque des règles
exécuté saufconditions
si toutes obligationfausses
:
• }//Fin bloc else 2
ne jamais utiliser de « else » sauf nécessité (rare) absolue !
• }//Fin bloc else 1

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 15/65


Programmation par règle pour un choix multiple (pas de else)

• En Python, la syntaxe est celle d'un choix :


• if condition1:
# bloc exécuté si condition1 est vraie
• if not condition1 and condition2:
# bloc exécuté si condition1 est fausse et condition2 est vraie
• if not condition1 and not condition2:
# bloc exécuté si toutes les conditions sont fausses
• L'équivalent Java est :
• if (condition1 == true) {
• //bloc exécuté si condition1 est vraie
• }
• if ((condition1 == false) && (condition2 == true)) {
• //bloc exécuté si condition1 est fausse et condition2 est
vraie
• }
• if ((condition1 == false) && (condition2 == false)){
• //bloc exécuté si toutes les conditions sont fausses
• }

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 16/65
Programmation par règle pour un choix multiple : philosophie KISS!

• La bonne manière de raisonner est de commencer par diagnostiquer la situation avant de prendre
une décision :
• int situation = 0 ;
• //Diagnosis
• if (condition1 == true) {
• situation = 1 ;
• }
• if ((condition1 == false) && (condition2 == true)) {
• situation = 2
• }
• //Decision
• if (situation == 0){
• //bloc exécuté dans la première situation
• }
• if (situation == 1){
• //bloc exécuté dans la deuxième situation
• }
• if (situation == 2){
• //bloc exécuté dans la troisième situation
• }

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 17/65


Programmation par règle pour un choix multiple : philosophie KISS!

• La bonne manière de raisonner est de commencer par diagnostiquer la situation avant de prendre
une décision :
• int situation = 0 ;
• //Diagnosis
• if (condition1 == true) {

Il ne faut pas s'y tromper : cette approche Diagnosis/Decision est générale
situation = 1 ;
• }

et bien plus claire que les idiomes proposés par les langages qui sont aussi
if ((condition1 == false) && (condition2 == true)) {
• situation = séduisants
2 que trompeurs !
• }

La programmation
//Decision
par règle vaut pour n (ici 3) comme pour 2 et 1, ce qui
• if (situation == 0){
• n'est pas le //bloc
cas avec les dans
exécuté langages qui imposent
la première situation de changer d'idiome !
• }
• Mais l'intérêt fondamental
if (situation == 1){ de cette manière de coder des choix multiples est de
• //bloc exécuté dans la deuxième situation

permettre
}
de faire évoluer indépendamment les connaissances de diagnostique
• if (situation == 2){ de celles de décision !
• //bloc exécuté dans la troisième situation
• }

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 18/65


Programmation Orientée Objet - Java

C01.2 : Substitution

Génie Informatique Industrielle

• Introduction sur ce qu'il faut oublier à propos de l'héritage ...


• Programmation par règles
• Factorisation de code
• Délégation et substitution
• Conclusion sur les deux (seuls) schémas à retenir ...

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 19/65


Factorisation de code en Java : les classes abstraites

• Java ayant été conçu pour un travail collaboratif distribué dans l'espace et dans le temps, la
factorisation de code est encouragée
• Tel est le rôle des classes abstraites : factoriser la déclaration d'attributs et de méthodes
• Les classes concrètes deviennent des composants : elles sont finales

Abstract classe AbstractArea


Longueur
largeur
extends

Final classes Rectangle Carre

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 20/65


Classe abstraite AbstractArea, un constructeur par défaut, des
membres en accès partagés (protected)

public abstract class AbstractArea {


//Constant
//Default values
private final Double LENGHT_DEFAULT_VALUE = 30.0d;
private final Double WIDTH_DEFAULT_VALUE = 15.0d;
private final String DEFAULT_NAME = "Rectangle";
//Rectangle Attributes
protected Double lenght = LENGHT_DEFAULT_VALUE;
protected Double width = WIDTH_DEFAULT_VALUE;
protected String name = DEFAULT_NAME;

//Default Constructor
protected Rectangle(Double length, Double width) {
this.lenght = length;
this.width = width;
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 21/65


Classe abstraite AbstractArea, getters et setters factorisés

//Getters and Setters public String getName() {


public Double getLenght() { return this.name;
return this.lenght; }
} public int setName(String name){
public int setLenght(Double length) { //Check for the definition domain
//Check for the definition domain if(name == null){
if (length <= 0) { System.out.println("setName(String name= null), name is
null ==> Do noting and return -1!");
System.out.println("setLenght(Double length=
"+length+")length is negative or null ==> Do noting and return -1!"); return -1;
return -1; }
} if(name.isEmpty() == true){
//All is ok System.out.println("setName(String name= ), name is empty
==> Do noting and return -2!");
this.lenght = length;
return -2;
return 1;
}
}
//All is ok
public Double getWidth() {
this.name = name;
return this.width;
return 1;
}
}
public int setWidth(Double width) {
//Check for the definition domain
if (width <= 0) {
System.out.println("setWidth(Double width= "+width+"),
width is negative or null ==> Do noting and return -1!");
return -1;
}
//All is ok
this.width = width;
return 1;
}
©Marc LE GOC 2025 - Programmation Orientée Objet - Java 22/65
et finalement, les sections toString et equals par défaut

//toString section //equals section


@Override @Override
public String toString() { public boolean equals(Object anObject) {
StringBuilder aStringBuilder = new StringBuilder(); //Check for the domain definition
if (anObject == null) {
aStringBuilder.append(DEFAULT_NAME); return false;
aStringBuilder.append(": "); }
aStringBuilder.append("name is "); //Check for the class
aStringBuilder.append(this.name); if (this.getClass() != anObject.getClass()) {
aStringBuilder.append(", lenght="); return false;
aStringBuilder.append(this.lenght); }
aStringBuilder.append(", width="); //Instances of the same class
aStringBuilder.append(this.width); final AbstractArea anotherAbstractArea = (AbstractArea)
anObject;
aStringBuilder.append(".");
//1°) Check for the name
if (this.name.equalsIgnoreCase(anotherAbstractArea.getName())
return aStringBuilder.toString();
== false) {
}
return false;
}
//2°) Same name ==> Check for the lenght and the width
if (this.lenght.equals(anotherAbstractArea.getLenght()) ==
false) {
return false;
}
return (this.width.equals(anotherAbstractArea.getWidth()));
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 23/65


Nouvelle classe Rectangle : final class BetterRectangle,
une méthode de fabrication !

public final class BetterRectangle extends AbstractArea {


//Constant
private final String DEFAULT_NAME = "BetterRectangle";
//Factory Method
public static AbstractArea getInstance(Double length, Double width) {
//Check for domain values
if (length <= 0.0) {
System.out.println("getInstance(Double length= "+length+", Double width= "+width+"), length is negative or null ==> return null!");
return null;
}
if (width <= 0.0) {
System.out.println("getInstance(Double length= "+length+", Double width= "+width+"), width is negative or null ==> return null!");
return null;
}
//All is ok ==> Build an instance
AbstractArea anAbstractArea = new BetterRectangle(length, width);
return anAbstractArea;
}
//Rectangle Attributes
//Constructor
private BetterRectangle(Double lenght, Double width) {
super(lenght, width);
this.name = DEFAULT_NAME;
}
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 24/65


Nouvelle classe Carre : final class BetterCarre, une
méthode de fabrication et son constructeur privé

public final BetterCarre extends AbstractArea{


//Constant
private final String DEFAULT_NAME = "BetterCarre";

//Factory Method
public static AbstractArea getInstance(Double side) {
//Check for domain values
if (side <= 0.0) {
System.out.println("getInstance(Double side= "+side+"), side is negative or null ==> return null!");
return null;
}
//All is ok ==> Build an instance
AbstractArea anAbstractArea = new BetterCarre(side);
return anAbstractArea;
}

//Constructor
private BetterCarre(Double side) {
super(side, side);
this.name = DEFAULT_NAME;
}

//Getters and Setters

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 25/65


Nouvelle classe Carre : final class BetterCarre, une
méthode de fabrication et son constructeur privé

//toString section //equals section


@Override @Override
public String toString() { public boolean equals(Object anObject) {
StringBuilder aStringBuilder = new StringBuilder(); //Check for the domain definition
if (anObject == null) {
aStringBuilder.append(DEFAULT_NAME); return false;
aStringBuilder.append(": "); }
aStringBuilder.append("name is "); //Check for the class
aStringBuilder.append(this.name); if (this.getClass() != anObject.getClass()) {
aStringBuilder.append(", side="); return false;
aStringBuilder.append(this.lenght); }
aStringBuilder.append("."); //Instances of the same class
final BetterCarre anotherCarre = (BetterCarre) anObject;
return aStringBuilder.toString(); //1°) Check for the name
} if (this.name.equalsIgnoreCase(anotherCarre.getName()) ==
false) {
return false;
}
//2°) Same name ==> Check for the side
return (this.lenght.equals(anotherCarre.getLenght()));
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 26/65


Programmation par composition d'interfaces : manipuler des types
abstraits de données

• Pour éviter la propagation des bugs, Java invite à la manipulation de types abstraits de
données définis par des interfaces

implements
interface Areable AbstractArea
//Constants
Abstract
Longueur
final Double LENGHT_DEFAULT_VALUE = 30.0d; largeur class
final Double WIDTH_DEFAULT_VALUE = 15.0d;

//Methods' signatures
extends
Double getLenght();

String getName();

Double getWidth();

int setLenght(Double length);


Rectangle Carre Losange
int setName(String name); ...
int setWidth(Double width);

Final classes
double getSurface();

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 27/65


L'interface Areable contient des constantes et des signatures de
méthodes


public interface Areable {
//Constants
La signature d'une méthode est la donnée
//Default values de :
final Double LENGHT_DEFAULT_VALUE = 30.0d;
final Double WIDTH_DEFAULT_VALUE = 15.0d; • son type de retour
//Methods Signatures • son nom
Double getLenght();
• La liste ordonnée de ses paramètres
String getName(); formels typés
Double getWidth();

int setLenght(Double length);

int setName(String name);

int setWidth(Double width);

double getSurface() ; implements


interface Areable AbstractArea
//Constants
Abstract
Longueur
final Double LENGHT_DEFAULT_VALUE = 30.0d; largeur class
} final Double WIDTH_DEFAULT_VALUE = 15.0d;

//Methods' signatures
extends
Double getLenght();

String getName();

Double getWidth();

int setLenght(Double length);


Rectangle Carre Losange
int setName(String name); ...
int setWidth(Double width);

Final classes
double getSurface();

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 28/65


La nouvelle classe abstraite AbstractKissArea implémente
Areable

public abstract class AbstractKissArea implements Areable {


//Constant
//Default values
private final String DEFAULT_NAME = "AbstractKissArea";

//AbstractArea Attributes
protected Double lenght = Areable.LENGHT_DEFAULT_VALUE;
protected Double width = Areable.WIDTH_DEFAULT_VALUE;
protected String name = DEFAULT_NAME;

//Constructor
protected AbstractKissArea(Double length, Double width) {
this.lenght = length;
this.width = width;
}

implements
interface Areable AbstractArea
//Constants
Abstract
Longueur
final Double LENGHT_DEFAULT_VALUE = 30.0d; largeur class
final Double WIDTH_DEFAULT_VALUE = 15.0d;

//Methods' signatures
extends
Double getLenght();

String getName();

Double getWidth();

int setLenght(Double length);


Rectangle Carre Losange
int setName(String name); ...
int setWidth(Double width);

Final classes
double getSurface();

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 29/65


Les getters et setters de la sont annotés @Override pour indiquer
qu'ils implémentent une interface

//Getters and Setters @Override


@Override public Double getWidth() {
public Double getLenght() { return this.width;
return this.lenght; }
} @Override
@Override public int setWidth(Double width) {
public int setLenght(Double length) { //Check for the definition domain
//Check for the definition domain if (width <= 0) {
if (length <= 0) { System.out.println("setWidth(Double width= "+width+"),
width is negative or null ==> Do noting and return -1!");
System.out.println("setLenght(Double length=
"+length+")length is negative or null ==> Do noting and return -1!"); return -1;
return -1; }
} //All is ok
//All is ok this.width = width;
this.lenght = length; return 1;
return 1; }
}

implements
interface Areable AbstractArea
//Constants
Abstract
Longueur
final Double LENGHT_DEFAULT_VALUE = 30.0d; largeur class
final Double WIDTH_DEFAULT_VALUE = 15.0d;

//Methods' signatures
extends
Double getLenght();

String getName();

Double getWidth();

int setLenght(Double length);


Rectangle Carre Losange
int setName(String name); ...
int setWidth(Double width);

Final classes
double getSurface();

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 30/65


Les getters et setters de la sont annotés @Override pour indiquer
qu'ils implémentent une interface

//Getters and Setters


@Override
public String getName() {
return this.name;
}
@Override
public int setName(String name){
//Check for the definition domain
if(name == null){
System.out.println("setName(String name= null), name is
null ==> Do noting and return -1!");
return -1;
}
if(name.isEmpty() == true){
System.out.println("setName(String name= ), name is empty
==> Do noting and return -2!");
return -2;
}
//All is ok
this.name = name;
implements
return 1; interface Areable AbstractArea
//Constants
Abstract
Longueur
} final Double LENGHT_DEFAULT_VALUE = 30.0d; largeur class
final Double WIDTH_DEFAULT_VALUE = 15.0d;

//Methods' signatures
extends
Double getLenght();

String getName();

Double getWidth();

int setLenght(Double length);


Rectangle Carre Losange
int setName(String name); ...
int setWidth(Double width);

Final classes
double getSurface();

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 31/65


et finalement, les sections toString et equals par défaut sont
inchangées

//toString section //equals section


@Override @Override
public String toString() { public boolean equals(Object anObject) {
StringBuilder aStringBuilder = new StringBuilder(); //Check for the domain definition
if (anObject == null) {
aStringBuilder.append(DEFAULT_NAME); return false;
aStringBuilder.append(": "); }
aStringBuilder.append("name is "); //Check for the class
aStringBuilder.append(this.name); if (this.getClass() != anObject.getClass()) {
aStringBuilder.append(", lenght="); return false;
aStringBuilder.append(this.lenght); }
aStringBuilder.append(", width="); //Instances of the same class
aStringBuilder.append(this.width); final AbstractArea anotherAbstractArea = (AbstractArea)
anObject;
aStringBuilder.append(".");
//1°) Check for the name
if (this.name.equalsIgnoreCase(anotherAbstractArea.getName())
return aStringBuilder.toString();
== false) {
}
return false;
}
//2°) Same name ==> Check for the lenght and the width
implements
interface Areable AbstractArea if (this.lenght.equals(anotherAbstractArea.getLenght()) ==
Abstract
//Constants
Longueur false) {
final Double LENGHT_DEFAULT_VALUE = 30.0d; largeur class
final Double WIDTH_DEFAULT_VALUE = 15.0d;
return false;
//Methods' signatures
extends }
Double getLenght();

String getName();
return (this.width.equals(anotherAbstractArea.getWidth()));
Double getWidth();
}
int setLenght(Double length);
Rectangle Carre Losange
int setName(String name); ...
int setWidth(Double width);
}
Final classes
double getSurface();

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 32/65


La signature de méthode de fabrication de la classe final class
KissRectangle change

public final class KissRectangle extends AbstractKissArea { //Specific Areable implementation


//Constant @Override
private final String DEFAULT_NAME = "KissRectangle"; public double getSurface() {
double surface = this.lenght*this.width;
//Factory Method return surface;
public static Areable getInstance(Double length, Double width) { }
//Check for domain values }
if (length <= 0.0) {
System.out.println("getInstance(Double length= "+length+",
Double width= "+width+"), length is negative or null ==> return
null!");
return null;
}
if (width <= 0.0) {
System.out.println("getInstance(Double length= "+length+",
Double width= "+width+"), width is negative or null ==> return null!");
return null;
}
//All is ok ==> Build an instance
Areable anAreable = new KissRectangle(length, width);
return anAreable; implements
interface Areable AbstractArea
Abstract
} //Constants
Longueur
final Double LENGHT_DEFAULT_VALUE = 30.0d; largeur class
//Rectangle Attributes final Double WIDTH_DEFAULT_VALUE = 15.0d;

//Methods' signatures
extends
Double getLenght();
//Constructor String getName();

private KissRectangle(Double lenght, Double width) { Double getWidth();

int setLenght(Double length);


super(lenght, width); int setName(String name);
Rectangle Carre Losange
...
this.name = DEFAULT_NAME; int setWidth(Double width);

Final classes
double getSurface();
}
©Marc LE GOC 2025 - Programmation Orientée Objet - Java 33/65
Idem pour la nouvelle version de la classe Carre : final class
KissCarre

public final class KissCarre extends AbstractKissArea{ //Specific Areable implementation


//Constant @Override
private final String DEFAULT_NAME = "BetterCarre"; public double getSurface() {
double surface = this.lenght*this.lenght;
//Factory Method return surface;
public static Areable getInstance(Double side) { }
//Check for domain values
if (side <= 0.0) {
System.out.println("getInstance(Double side= "+side+"),
side is negative or null ==> return null!");
return null;
}
//All is ok ==> Build an instance
Areable anAreable = new KissCarre(side);
return anAreable;
}

//Constructor
private KissCarre(Double side) {
super(side, side); implements
interface Areable AbstractArea
this.name = DEFAULT_NAME; //Constants
Abstract
Longueur
largeur class
} final Double LENGHT_DEFAULT_VALUE = 30.0d;

final Double WIDTH_DEFAULT_VALUE = 15.0d;

//Methods' signatures
extends
//Getters and Setters Double getLenght();

String getName();

Double getWidth();

int setLenght(Double length);


Rectangle Carre Losange
int setName(String name); ...
int setWidth(Double width);

Final classes
double getSurface();

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 34/65


Nouvelle classe Carre : final class BetterCarre, une
méthode de fabrication et son constructeur privé

//toString section //equals section


@Override @Override
public String toString() { public boolean equals(Object anObject) {
StringBuilder aStringBuilder = new StringBuilder(); //Check for the domain definition
if (anObject == null) {
aStringBuilder.append(DEFAULT_NAME); return false;
aStringBuilder.append(": "); }
aStringBuilder.append("name is "); //Check for the class
aStringBuilder.append(this.name); if (this.getClass() != anObject.getClass()) {
aStringBuilder.append(", side="); return false;
aStringBuilder.append(this.lenght); }
aStringBuilder.append("."); //Instances of the same class
final BetterCarre anotherCarre = (BetterCarre) anObject;
return aStringBuilder.toString(); //1°) Check for the name
} if (this.name.equalsIgnoreCase(anotherCarre.getName()) ==
false) {
return false;
}
//2°) Same name ==> Check for the side

implements return (this.lenght.equals(anotherCarre.getLenght()));


interface Areable AbstractArea
//Constants
Abstract }
Longueur
final Double LENGHT_DEFAULT_VALUE = 30.0d; largeur class
final Double WIDTH_DEFAULT_VALUE = 15.0d;

//Methods' signatures
}
extends
Double getLenght();

String getName();

Double getWidth();

int setLenght(Double length);


Rectangle Carre Losange
int setName(String name); ...
int setWidth(Double width);

Final classes
double getSurface();

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 35/65


La programmation par composition d'interfaces est un processus
d’abstraction/réification successives

L’interface est une abstraction des classes final qui définit un ensemble
de composants en intension
implements
interface Areable AbstractArea
//Constants
Abstract
Longueur
final Double LENGHT_DEFAULT_VALUE = 30.0d; largeur class
final Double WIDTH_DEFAULT_VALUE = 15.0d;
extends
//Methods' signatures

Double getLenght();

String getName();

Double getWidth();
Rectangle Carre Losange
int setLenght(Double length); ...
int setName(String name);

int setWidth(Double width);

double getSurface();
Les classes final sont une réification de
l’interface, c-à-d un ensemble de composants
définit en extension
©Marc LE GOC 2025 - Programmation Orientée Objet - Java 36/65
Programmation Orientée Objet - Java

C01.2 : Substitution

Génie Informatique Industrielle

• Introduction sur ce qu'il faut oublier à propos de l'héritage ...


• Programmation par règles
• Factorisation de code
• Délégation et substitution
• Conclusion sur les deux (seuls) schémas à retenir ...

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 37/65


Au sens informatique du terme, un objet est toujours une
instance (i.e. un exemple)

• Lorsque l'on dit que « xi est un objet de la classe CX », on veut dire que la classe CX est
habilitée à créer des instances xi de l'interface IX de la classe CX
• Cela signifie que xi est un des éléments de l'ensemble X définit par les méthodes
déclarées dans l'interface IX

CX

IX
p1(x)
X ForAll xi obs_1 μ1 μ1(p1(xi))
p2(x)
obs_2 μ2 μ2(p2(xi))

...
p2(x)
obs_n μn μn(pn(xi))

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 38/65


Relation entre objets, interface et classe

• En informatique, le concept d'ensemble dénombrable X={xi} est construit à


partir de la définition d'une interface IX qui spécifie un ensemble M={μk} de
fonctions de mesure μk permettant l'observation d'un ensemble P={pk} de
propriétés quantifiables pk dont les valeurs sont éventuellement mémorisées
dans la structure (i.e. le frame) définie par une classe CX
IX CX

μ1 μ1(p1)

μ2 μ2(p2)
X xi
... ...
μn μn(pn)

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 39/65


Relation entre instance, interface et classe

• La relation entre une instance et une classe est une relation de création
• Les classes sont seules habilités à créer des instances
• La relation entre une classe et une interface est une relation d'implémentation
• Une classe implémente au moins une interface
• La relation entre une instance et une interface est une relation d'appartenance
• xi∈X ⇔ xi estUn Xable ⇔ xi instanceof Xable

X IX X IX
IX
CX

μ1 μ1(p1)

μ2 μ2(p2)
CX X
... ...
xi

μn μn(pn)

x1 x2 ... xi x1 x2 ... xi

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 40/65


L'appartenance à un ensemble est une relation « estUn » (« isa » en
anglais)

• L'appartenance à un ensemble est une relation « estUn » (« isa » en anglais) :


• x appartient à X ⇔ x∈X ⇔ x estUn X
• En Java, x estUn X ⇔ (anXable instanceof Xable) == true
• La spécialisation d'un type abstrait de données étend (extends) l'ensemble des fonctions de
mesure et donc restreint le périmètre des éléments concernés :
• (y∈Y ⇒ y∈X) ⇔ (y estUn Y ⇒ y estUn X) ⇔ Y⊂X
• Yable extends Xable ⇔ (anYable instanceof Xable) == true
• Par conséquent, un élément qui satisfait les contraintes d'un ensemble de n interfaces appartient
à l'intersection de n ensembles

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 41/65


Exemple : un carré est-il un rectangle qui se tient à carreau ou un
losange qui a mal tourné ?

Rectangle Losange Losange Rectangle Rectangle

Carre Carre Rectangle Losange Carre

Carre Carre Losange

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 42/65


Exemple ... typique d’un problème mal posé !

Rectangle Losange Losange Rectangle Rectangle

Carre Carre Rectangle Losange Carre

Carre Carre Losange

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 43/65


Un carré, un rectangle ou un losange est un quadrilatère, c-à-d un
polygone à quatre cotés

Concept générique
Polygonable AbstractPolygone
implements abstract class

extends

Trapeze Carre Rectangle Losange Parallélogramme


...

Concepts spécifiques final classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 44/65


Autre exemple : aClassC est un exemplaire d'un concept ...
abominable !
implements
Objectable Object

extends extends
implements implements
Aable ClassA Dable ClassD

extends extends
implements implements implements
Bable ClassB Iable ClassE
Eable
extends extends
implements implements
Cable ClassC Fable ClassF

aClassC est un Cable, Bable, Aable, Iable, Eable, Dable et un Objectable !

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 45/65


Cet exemple illustre la programmation objet des années 80, celle
pratiquée par vos grands parents !
implements
Objectable Object

extends extends
implements implements
Aable ClassA Dable ClassD

extends extends
implements implements implements
Bable ClassB Iable ClassE
Eable
extends extends
implements implements
Cable ClassC Fable ClassF

aClassC est un Cable, Bable, Aable, Iable, Eable, Dable et un Objectable !

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 46/65


Aux hasards de l'héritage, on préfère aujourd'hui la composition
d'interfaces : Schéma n°1

• Les comportements complexes, spéciaux ou exceptionnels sont codés dans des classes finalisées
(i.e. non héritables) qui se contentent d'implémenter des interfaces
• Le contrôleur ne connait que l'interface de son délégué, c'est-à-dire uniquement les
signatures des méthodes de l'interface Delegable
• Les classes finalisées implémentent Delegable indépendamment les unes des autres
aDelegable
Controler Delegable
anOperation() anOperation()

this.aDelegable.anOperation() ;
implements

Final ComponentA ComponentB ... ComponentI ... ComponentN


classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 47/65


Structure prototypique du code d'un délégué : version Schéma n°1
(sans factorisation de code)

public final class Delegate implements Delegable { //Object Section


//Constants @Override
private static final String DEFAULT_NAME = "Delegate"; public String toString(){
private static final Reporter R = StringBuilder aStringBuilder = new StringBuilder() ;
Reporter.getaReporter(DEFAULT_NAME) ;
//Factory Methods aStringBuilder.append(DEFAULT_NAME) ;
public Delegable getInstance(String aString){ aStringBuilder.append(" is: ") ;
if(aString == null){ aStringBuilder.append(this.name) ;
R.reportError("getInstance(String aString= null), aString is aStringBuilder.append(".") ;
null ==> Retun a null instance!") ;
return null ; return aStringBuilder.toString() ;
} }
if(aString.isEmpty() == true){
@Override
R.reportError("getInstance(String aString= ), aString is empty
public equals(Object anObject){
==> use the default name " +DEFAULT_NAME+ "!") ;
if (this == anObject) { return true; }
aString = DEFAULT_NAME ;
if (anObject == null) { return false; }
}
if ((anObject instanceof Delegable) == false) {
//All is ok ==> Build an instance
return false;
Delegable aDelegable = new Delegate(aString) ;
}
return aDelegable;
final Delegable anotherDelegable = (Delegable) anObject ;
}
return (this.name.equalsIngnoreCase(anotherDelegable.getName()) ;
//Attributes
}
private final String name ;
//Constructors
}
private Delegate(String name){
this.name = name ;
}

//Delegable Section
@Override
public String getName() {
return this.name ;
}
@Override
public int anOperation() {
...
return 1 ;
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 48/65


Aux hasards de l'héritage, on préfère aujourd'hui la composition
d'interfaces : Schéma n°2

• S'il est avantageux ou nécessaire de factoriser du code, on implémente l'interface du délégué


dans une classe abstraite
• La classe abstraite contient le code commun à tous les composants (i.e. toutes les classes
finalisées

aDelegable implements
Controler Delegable AbstractDelegate
anOperation() anOperation() anOperation()

this.aDelegable.anOperation() ;
extends

Final Component1 Component2 ... ComponentI ... ComponentN


classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 49/65


Structure prototypique du code d'un délégué : version Schéma n°2
(avec factorisation de code)

public abstract class AbstractDelegate implements Delegable { //Object Section


//Constants @Override
private static final String DEFAULT_NAME = "AbstractDelegate"; public String toString(){
StringBuilder aStringBuilder = new StringBuilder() ;
private static final Reporter R =
Reporter.getaReporter(DEFAULT_NAME) ; aStringBuilder.append(DEFAULT_NAME) ;
aStringBuilder.append(" is: ") ;
//Attributes aStringBuilder.append(this.name) ;
protected String name ; aStringBuilder.append(".") ;

//Delegable Section return aStringBuilder.toString() ;


@Override }
public String getName() { @Override
return this.name ; public equals(Object anObject){
} if (this == anObject) { return true; }
if (anObject == null) { return false; }
if ((anObject instanceof Delegable) == false) {
return false;
}
final Delegable anotherDelegable = (Delegable) anObject ;
return (this.name.equalsIngnoreCase(anotherDelegable.getName()) ;
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 50/65


Structure prototypique du code d'un délégué : version Schéma n°2
(avec factorisation de code)

public final class Delegate extends AbstractDelegate {


//Constants
private static final String DEFAULT_NAME = "Delegate";
private static final Reporter R = Reporter.getaReporter(DEFAULT_NAME) ;
//Factory Methods
public Delegable getInstance(String aString){
if(aName == null){
R.reportError("getInstance(String aString= null), aString is null ==> Retun a null instance!") ;
return null ;
}
if(aName.isEmpty() == true){
R.reportError("getInstance(String aString= ), aString is empty ==> use the default name " +DEFAULT_NAME+
"!") ;
aString = DEFAULT_NAME ;
}
//All is ok ==> Build an instance
Delegable aDelegable = new Delegate(aString) ;
return aDelegable;
}
//Constructors
private Delegate(String name){
this.name = name ;
}
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 51/65


Programmation par composition d'interfaces : Délégation et
substitution

aDelegable
Controler Delegable
anOperation() anOperation() Schéma 1 :
this.aDelegable.anOperation() ; Délégation et
implements
Substitution sans
factorisation de code
Final ComponentA ComponentB ... ComponentI ... ComponentN
classes

aDelegable implements
Controler Delegable AbstractDelegate
anOperation() anOperation() anOperation()
Schéma 2 :
this.aDelegable.anOperation() ;
extends
Délégation et
Substitution avec
factorisation de code
Final ComponentA ComponentB ... ComponentI ... ComponentN
classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 52/65


Intérêt de la programmation par composition d'interfaces :
indépendance des composants

• Le code est plus facile à lire (localité et unicité)


• Il est très facile d'ajouter ou de supprimer des composants (final class)
• Il est très facile de modifier ou d'ajouter des comportements (méthodes)

aDelegable implements
Controler Delegable AbstractDelegate

anOperation() anOperation() anOperation()


anotherOperation() anotherOperation() anotherOperation()

this.aDelegable.anOperation() ;

this.aDelegable.anotherOperation() ; extends

Final Component1 ... ComponentI ... ComponentN ComponentN+1

classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 53/65


Intérêt des interfaces : appliquer à Java les principes de délégation
et de substitution

• Ce principe fondamental fait intervenir un utilisateur, ici une instance de Controler, qui veut
exécuter anOperation :
• Elle est déléguée à une classe concrète ComponentA ou ComponentB sans que
l'utilisateur sache forcément laquelle !
• L'opération anOperation du Controler est substituée par celle du délégué
• Une classe abstraite est utilisée pour factoriser le code commun à tous les composants

aDelegable implements
Controler Delegable AbstractDelagate
anOperation() anOperation() anOperation()

this.aDelegable.anOperation() ; extends

Final classes ComponentA ComponentB

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 54/65


Si aucune factorisation n'est nécessaire, l'interface est directement
implémentée dans les composants

• Le contrôleur ne connait que le type abstrait de son délégué, c'est-à-dire les signatures des
méthodes de l'interface Delegable !

aDelegable
Controler Delegable
anOperation() anOperation()
implements
this.aDelegable.anOperation() ;

Final classes ComponentA ComponentB

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 55/65


Exemple de mise en oeuvre : la méthode de fabrication du
contrôleur choisit son délégué

public final class Controler { if(anAreable == null){


//Constants System.out.println("getInstance(Double length= " + length +
", Double width= " + width + "), anAreable is null ==> Return a null
private static final double ZERO_ASA_DOUBLE = 0.0d;
Controler!");
//Factory method
return null;
public static Controler newInstance(Double length, Double width) {
}
//Check for domain values
//All is ok ==> build a conform instance
if (length <= 0.0) {
Controler aControler = new Controler(anAreable);
System.out.println("getInstance(Double length= " + length +
return aControler;
", Double width= " + width + "), length is negative or null ==> return
null!"); }
return null; //Delegate
} private Areable anAreable;
if (width <= 0.0) {
System.out.println("getInstance(Double length= " + length + //Constructor
", Double width= " + width + "), width is negative or null ==> return
public Controler(Areable anAreable) {
null!");
this.anAreable = anAreable;
return null;
}
}
//All is ok ==> Try to build an instance
Areable anAreable = null;
//length == width ==> Build a carre
if (length == width) {
anAreable = KissCarre.getInstance(length);
}
//length != width ==> Build a rectangle
if (length != width) {
anAreable = KissRectangle.getInstance(length, width);
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 56/65


Intérêt de la délégation : le code est hautement dynamique

//Controler operations public int changeDelegate(Areable anAreable){

public double getSurface() { //Check for the domain definition

if (this.anAreable != null) { if(anAreable == null){

return this.anAreable.getSurface(); System.out.println("changeDelegate(Areable anAreable=


null), anAreable is null ==> Do noting and return -1!");
}
return -1;
//anAreable is null
}
System.out.println("getSurface(), anAreable is null ==> Do
noting and return 0.0!"); //Same delegate ==> Do noting and return 0!

return ZERO_ASA_DOUBLE; if(this.anAreable.equals(anAreable) == true){

} System.out.println("changeDelegate(Areable anAreable=
"+anAreable.toString()+"), anAreable is equals to this
"+this.anAreable.toString()+" ==> Do noting and return 0!");
return 0;
}
//All is ok ==> change the delegate
this.anAreable = anAreable;
return 1;
}

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 57/65


Intérêt de la délégation : le code est hautement dynamique

//Controler operations public int changeDelegate(Areable anAreable){

public double getSurface() { //Check for the domain definition

if (this.anAreable != null) { if(anAreable == null){

return this.anAreable.getSurface(); System.out.println("changeDelegate(Areable anAreable=


null), anAreable is null ==> Do noting and return -1!");
}
return -1;
//anAreable is null
}
System.out.println("getSurface(), anAreable is null ==> Do
noting and return 0.0!"); //Same delegate ==> Do noting and return 0!

return ZERO_ASA_DOUBLE; if(this.anAreable.equals(anAreable) == true){

} System.out.println("changeDelegate(Areable anAreable=
"+anAreable.toString()+"), anAreable is equals to this
Attention : il ne s'agit que d'une illustration, ici maladroite, des principes
"+this.anAreable.toString()+" ==> Do noting and return 0!");
return 0;
de délégation et de substitution qui sont à la base de la programmation }

d'aujourd'hui.
//All is ok ==> change the delegate
this.anAreable = anAreable;
return 1;
}
Ces principes privilégient la composition d'interface au détriment de
l'héritage. Nous reviendrons sur ces principes en 4ième année ... et dans le
}

TD3 !

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 58/65


Programmation Orientée Objet - Java

C01.2 : Substitution

Génie Informatique Industrielle

• Introduction sur ce qu'il faut oublier à propos de l'héritage ...


• Programmation par règles
• Factorisation de code
• Délégation et substitution
• Conclusion sur les deux (seuls) schémas à retenir ...

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 59/65


Programmation par composition d'interfaces : Délégation et
substitution

aDelegable
Controler Delegable
anOperation() anOperation() Schéma 1 :
this.aDelegable.anOperation() ; Délégation et
implements
Substitution sans
factorisation de code
Final ComponentA ComponentB ... ComponentI ... ComponentN
classes

aDelegable implements
Controler Delegable AbstractDelegate
anOperation() anOperation() anOperation()
Schéma 2 :
this.aDelegable.anOperation() ;
extends
Délégation et
Substitution avec
factorisation de code
Final ComponentA ComponentB ... ComponentI ... ComponentN
classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 60/65


Intérêt de la programmation par composition d'interfaces :
indépendance des composants

• Le code est plus facile à lire (localité et unicité)


• Il est très facile d'ajouter ou de supprimer des composants (final class)
• Il est très facile de modifier ou d'ajouter des comportements (méthodes)

aDelegable implements
Controler Delegable AbstractDelegate
anOperation() anOperation() anOperation()
anotherOperation()
this.aDelegable.anOperation() ;
extends

Final ComponentB ... ComponentI ... ComponentN ComponentN+1


classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 61/65


En synthèse, la programmation en Java est plus industrielle que
celle en Python

• Python est efficace pour développer des prototypes centrés sur l'analyse de données (cf.
https://covidtracker.fr/ par exemple)
• La programmeuse ou le programmeur Python est une ou un adulte consentant
• Sa responsabilité est pleine et entière !
• Le débugage des programmes Python est aussi pythonesque que sa syntaxe
• Les bugs ne sortent qu'à l'exécution !!!! Et ils ne sont pas facile à diagnostiquer !
• A la date de rédaction de ce transparent, le 31/01/2022, Python n'est pas ou peu intégrable
dans des applications temps réel, embarquées ou non
• Java est un langage qui impose à la programmeuse et au programmeur d'être pleinement
conscient des types abstraits des données qu'il manipule
• Le but de la programmeuse ou du programmeur habile est de contraindre le compilateur
à faire le maximum de vérifications a priori possible
• Il est ainsi possible de programmer en Java sans faire de bug
• C'est l'approche KISS, Keep It Simple, Stupid!

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 62/65


A ce stade du cours, vous savez tout … sauf énumérer les éléments
d’un ensemble !

• Tout langage informatique propose un lexique, une grammaire et une sémantique pour coder :
• 1°) la fabrication xi∈X d'éléments xi d'un ensemble X définit en intension par une
interface Xable,
• 2°) l’assignation x=←xi d’une valeur xi à une variable x,
• 3°) le test de l'égalité x == xi entre deux valeurs et
• 4°) des règles « Si ... alors ... » du langage courant sous la forme de l’implication (x == xi)
⇒ (y←yj) d’une assignation y←yj à partir d’une égalité x == xi

aDelegable aDelegable implements


Controler Delegable Controler Delegable AbstractDelegate
anOperation() anOperation() anOperation() anOperation() anOperation()

this.aDelegable.anOperation() ; this.aDelegable.anOperation() ;
implements extends

Final ComponentA ComponentB ... ComponentI ... ComponentN Final ComponentA ComponentB ... ComponentI ... ComponentN
classes classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 63/65


A ce stade du cours, vous savez tout … sauf énumérer les éléments
d’un ensemble !

• Tout langage à objets permet la programmation par composition d’interfaces, c-à-d


l’implémentation de l’un ou l’autre des deux schémas de délégation et de substitution avec ou
sans factorisation de code dans une classe abstraite

aDelegable aDelegable implements


Controler Delegable Controler Delegable AbstractDelegate
anOperation() anOperation() anOperation() anOperation() anOperation()

this.aDelegable.anOperation() ; this.aDelegable.anOperation() ;
implements extends

Final ComponentA ComponentB ... ComponentI ... ComponentN Final ComponentA ComponentB ... ComponentI ... ComponentN
classes classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 64/65


On passe des final classes à l’interface par abstraction, on fait
l’inverse par réification

Intension
Ensemble de propriétés

Abstraction

Fonctions
Structure Variable
Nombre
Comportement
Réification

Extension
Ensemble d’éléments E={ei}

aDelegable aDelegable implements


Controler Delegable Controler Delegable AbstractDelegate
anOperation() anOperation() anOperation() anOperation() anOperation()

this.aDelegable.anOperation() ; this.aDelegable.anOperation() ;
implements extends

Final ComponentA ComponentB ... ComponentI ... ComponentN Final ComponentA ComponentB ... ComponentI ... ComponentN
classes classes

©Marc LE GOC 2025 - Programmation Orientée Objet - Java 65/65

Vous aimerez peut-être aussi