Vous êtes sur la page 1sur 69

Programmation Windows

Programmation Orientée Objet


POO
Enseignant
Willy-joël TCHANA
Ingénieur logiciel : Architecte logiciel
Directeur Over Soft Solution

1 @willytchana @osschannel +237 677 392 752


2 Agenda

 Introduction
 Classe & objet
 Encapsulation
 Héritage 

 Polymorphisme
 Classe abstraite
 Interface
 Relation entre classe
 Généricité
3 Introduction

 La programmation orientée objet, souvent abrégée POO, permet de


concevoir une application sous la forme d'un ensemble de briques
logicielles appelées des objets.
 Chaque objet joue un rôle précis et peut communiquer avec les autres
objets
 Les interactions entre les différents objets vont permettre à l'application
de réaliser les fonctionnalités attendues.
 La POO facilite la conception de programmes par réutilisation de
composants existants
 Elle constitue le standard actuel (on parle de paradigme) en matière de
développement de logiciels.
Classe & objet
4 La notion d’objet
 En POO, on cherche à représenter le domaine étudié sous la forme d'objets. C'est la phase de modélisation
orientée objet.
 Un objet est une entité qui représente (modélise) un élément du domaine étudié :
 une voiture, un compte bancaire, un nombre complexe, une facture, etc.
 Objet = état + actions
 En première approche, on peut considérer qu'un compte bancaire est caractérisé par:
 Un titulaire, un solde (le montant disponible sur le compte) et utilise une certaine devise (euros,
dollars, etc)
 Les actions réalisables sur un compte sont le dépôt d'argent (crédit) et le retrait (débit).
 un objet se compose d'informations et d'actions. Les actions utilisent (et parfois modifient) les
informations de l'objet.
 L'ensemble des informations d'un objet donné est appelée son état.
 L'ensemble des actions applicables à un objet représente son comportement.
 REMARQUE : les actions associées à un objet s'expriment généralement sous la forme de verbes à
l'infinitif (créditer, débiter).
Classe & objet
5 La notion de classe
 une classe est un modèle d'objet.
 C'est un nouveau type de données créé par le programmeur et qui sert
de modèle pour tous les objets de cette classe.
 Une classe spécifie les informations et les actions qu'auront en commun
tous les objets qui en sont issus.
 En utilisant le vocabulaire de la POO, on dit que l'objet est
une instance d’une classe.
Class & object
Représentation graphique
6
 Afin de faciliter la communication entre les programmeurs n'utilisant pas le même langage de programmation objet, il
existe un standard de représentation graphique d'une classe.
 Ce standard fait partie de la norme UML (Unified Modeling Language). On parle de diagramme de classe.

 Quel que soit l'outil utilisé, on observe que la classe est décomposée en deux parties :
 les champs attributs ou propriétés, qui correspondent aux informations de la classe : devise, solde et titulaire.
 les méthodes, qui correspondent aux actions réalisables: créditer, débiter et décrire.

 Attention, le terme de propriétés est ambigu en C#


Class & object
Exemple
7
public class CompteBancaire
{
public string titulaire;
public double solde;
public string devise;

public void Crediter(double montant)


{
solde = solde + montant;
}
public void Debiter(double montant)
{
solde = solde - montant;
}
}
Class & object
Instanciation et utilisation
8 class Program
{
static void Main(string[] args)
{
CompteBancaire comptePierre; // déclaration d'un nouvel objet
comptePierre = new CompteBancaire(); // instanciation de cet objet
// affectations de valeurs aux attributs
comptePierre.titulaire = "Pierre";
comptePierre.solde = 0;
comptePierre.devise = "euros";
// appels des méthodes
comptePierre.Crediter(300);
comptePierre.Debiter(500);
string description = "Le solde du compte de " + comptePierre.titulaire +
" est de " + comptePierre.solde + " " + comptePierre.devise;
Console.WriteLine(description);
}
Class & object
Résultat

9
Class & object
Ajout d’une méthode

10
public class CompteBancaire
{
// ...

// Renvoie la description d'un compte


public string Decrire()
{
string description = "Le solde du compte de " + titulaire + " est de " + solde + " " + devise;
return description;
}
}
Class & object
Plusieurs instances

11 static void Main(string[] args)


{
CompteBancaire comptePierre = new CompteBancaire();
comptePierre.titulaire = "Pierre";
comptePierre.solde = 500;
comptePierre.devise = "euros";
CompteBancaire comptePaul = new CompteBancaire();
comptePaul.titulaire = "Paul";
comptePaul.solde = 150;
comptePaul.devise = "euros";
Console.Write("Entrez le montant du transfert : ");
double montantTransfert = Convert.ToDouble(Console.ReadLine());
comptePierre.Debiter(montantTransfert);
comptePaul.Crediter(montantTransfert);
Console.WriteLine(comptePierre.Decrire());
Console.WriteLine(comptePaul.Decrire());
}
Class & object
Résultat

12
Classe & objet
13 Le constructeur
 On peut partir du principe que:
 Tout compte a nécessairement un titulaire, un solde initial et une devise lors de sa création.
 On aimerait pouvoir instancier un objet de la classe CompteBancaire en définissant
directement les valeurs de ses attributs.
 Pour cela, nous allons ajouter à notre classe une méthode particulière : le constructeur.
 Le constructeur est une méthode spécifique dont le rôle est de construire un objet, le plus
souvent en initialisant ses attributs.
 En C#:
 le nom du constructeur doit être identique au nom de la classe, et sa définition ne comporte pas de
type de retour.
 L'utilisation d'un constructeur se fait au moment de l'instanciation de l'objet (opérateur
new), en passant en paramètres les futures valeurs des attributs de l'objet créé.
Classe & objet
14 Constructeur : Exemple
public class CompteBancaire
{
public string titulaire;
public double solde;
public string devise;

// Constructeur
public CompteBancaire(string leTitulaire, double soldeInitial, string laDevise)
{
titulaire = leTitulaire;
solde = soldeInitial;
devise = laDevise;
}
// ...
Classe & objet
15 Constructeur : Exemple
// déclaration et instanciation d'un nouvel objet en utilisant son
constructeur
CompteBancaire comptePierre = new CompteBancaire("Pierre", 0, "euros");

// appels de méthodes
comptePierre.Crediter(300);
comptePierre.Debiter(500);
Console.WriteLine(comptePierre.Decrire());
Classe & objet
Le Constructeur par défaut
16
 Lorsqu'une classe ne définit aucun constructeur (comme dans l'exemple du chapitre précédent),
un constructeur par défaut sans aucun paramètre est implicitement créé.
 Il n'a aucun comportement mais son existence permet d'instancier des objets de cette classe.
 En revanche, toute définition explicite d'un constructeur dans une classe "désactive" le
constructeur par défaut.

 REMARQUE : une classe peut disposer de plusieurs constructeurs initialisant différents


attributs: surcharge du constructeur
Classe & objet
Autoréférence : le mot clé this
17
 A l'intérieur d'une méthode, le mot-clé this permet d'accéder à l'instance (l'objet) sur lequel la
méthode est appelée.
 L'une des utilisations fréquentes de this consiste à lever les ambiguïtés de nommage entre
attributs et paramètres.
 Il permet aussi d’appeler un autre constructeur (en cas de surcharge) mais en respectant
certaines règles.

public CompteBancaire(string titulaire, double soldeInitial, string devise)


{
this.titulaire = titulaire;
solde = soldeInitial;
this.devise = devise;
}
Classe & objet
Autoréférence : le mot clé this
18
public CompteBancaire(string titulaire, string devise)
{
this.titulaire = titulaire;
this.devise = devise;
solde = 0;
}

public CompteBancaire(string titulaire, string devise, double soldeInitial) : this(titulaire,


devise)
{
solde = soldeInitial;
}
Encapsulation
19 Principe 
 La possibilité de restreindre l'accès à certains éléments de la classe est ce qu'on
appelle l'encapsulation.
 Pour y arriver on utilise la notion visibilité vue au chapitre précédent
 Le but majeur est de maintenir la cohérence des objets
public class CompteBancaire

private string titulaire; // attribut privé

public double solde;

private string devise; // attribut privé

public CompteBancaire(string leTitulaire, double soldeInitial, string laDevise)

titulaire = leTitulaire;

solde = soldeInitial;

devise = laDevise;

// ...
Encapsulation
20 Principe 
 l'encapsulation est l'un des principes fondamentaux de la POO. Il consiste à restreindre l'accès à certains
éléments d'une classe (le plus souvent ses attributs).
 L'objectif de l'encapsulation est de ne laisser accessible que le strict nécessaire pour que la classe soit
utilisable.
class Program
{
static void Main(string[] args)
{
CompteBancaire comptePierre = new CompteBancaire("Pierre", 0, "euros");
comptePierre.titulaire = "Jean"; // Erreur : titulaire est un attribut privé
comptePierre.solde = 500; // OK : solde est un attribut public
comptePierre.devise = "euros"; // Erreur : devise est un attribut privé
}
}
Encapsulation
21 Principe 
 CONSEIL : sauf cas particulier, on donne le niveau de visibilité private à tous les attributs d'une classe
afin d'assurer leur encapsulation par défaut.
public class CompteBancaire
{
private string titulaire;
private double solde;
private string devise;
public CompteBancaire(string titulaire, double solde, string devise)
{
this.titulaire = titulaire;
this.solde = solde;
this.devise = devise;
}
// ...
Encapsulation
22 Avantages 

 Diminution des risques de mauvaise manipulation


d'une classe.
 Création de classes "boîtes noires" par masquage des
détails internes.
 Possibilité de modifier les détails internes d'une
classe (la manière dont elle fonctionne) sans changer
son comportement extérieur (ce qu'elle permet de
faire).
Encapsulation
23 Bien comprendre 
public class CompteBancaire
{
private string titulaire;
private double solde;
private string devise;
public CompteBancaire(CompteBancaire compte)
{
this.titulaire = compte.titulaire;
this.devise = compte.devise;
this.solde = compte.solde;
}
// ...
Encapsulation
24 Accesseur & mutateur 
 Une fois l’objet créé, comment retourner ou modifier son état?
 Pour cela on utilise respectivement des accesseurs ou des mutateurs
 Un accesseur (getter) permet de lire la valeur d'un attribut. C’est une méthode publique qui ne prend
aucun paramètre et qui retourne l’attribut qu’il encapsule
 En C# les accesseurs sont préfixés par Get
 Ex: public string GetTitulaire();
 un mutateur (setter) permet de modifier la valeur d'un attribut. C’est une méthode publique qui prend en
paramètre la nouvelle valeur de l’attribut à modifier et ne retourne rien
 En C# les mutateurs sont préfixés par Set
 Ex: public void SetTitulaire(string nouveauTitulaire);
Encapsulation
25 Accesseur & mutateur 
public class CompteBancaire
{
private string titulaire;
private double solde;
private string devise;
//Accesseur
public string GetTitulaire()
{
return titulaire;
}
//mutateur
public void SetTitulaire(string nouveauTitulaire)
{
titulaire = nouveauTitulaire;
}
Encapsulation
26 Accesseur & mutateur 
class Program
{
static void Main(string[] args)
{
CompteBancaire comptePierre = new CompteBancaire("Pierre", "euros", 0);
comptePierre.SetTitulaire("Jean"); // Setter
string nom = comptePierre.GetTitulaire(); // Getter
}
}
Encapsulation
27 Particularité du C# 
 Le C# distingue les attributs des propriétés d’un objet.
 Les attributs sont champs privés (private)
 Tandis que les propriétés sont les accesseurs et mutateurs
 En plus langage propose un syntaxe permettant de les
regroupés sous un même nom et déduira le méthodes
adéquate lors de l’appel.
 Cette prouesse est réalisée par les mots clé get, set et
value
Encapsulation
28 Particularité du C# 
public class CompteBancaire
{
private string titulaire;
private double solde;
private string devise;
public string Titulaire
{
get
{
return titulaire;
}
set
{
titulaire = value;
}
}
Encapsulation
Particularité du C# 
29
 Si la propriété ne se contente que retourner ou de modifier l’attribut, il n’est même pas nécessaire de créer cette attribut,
le compilateur le fera implicitement: parle alors de propriété automatique
public class CompteBancaire

public string Titulaire

get;

set;

//public string Titulaire{ get; set; }


public CompteBancaire(string titulaire, string devise)

Titulaire = titulaire;

public string Decrire()

string description = "Le solde du compte de " + Titulaire + " est de " + solde + " " + devise;

return description;

}
public class CompteBancaire

public string Titulaire { get; set; }

public double Solde { get; set; }


30 public string Devise { get; set; }

public CompteBancaire(string titulaire, string devise)

Titulaire = titulaire;

Devise = devise;

Solde = 0;

public CompteBancaire(string titulaire, string devise, double solde) : this(titulaire, devise)

Solde = solde;

public void Crediter(double montant)

Solde += montant;

public void Debiter(double montant)

Solde -= montant;

public string Decrire()

string description = "Le solde du compte de " + Titulaire + " est de " + Solde + " " + Devise;

return description;
Encapsulation
31
Particularité du C# 
public class CompteBancaire
{
public string Titulaire { get; set; }
public double Solde { get; set; }
public string Devise { get; set; }
public CompteBancaire(string titulaire, string devise)
{
Titulaire = titulaire;
Devise = devise;
Solde = 0;
}
public CompteBancaire(string titulaire, string devise, double solde) : this(titulaire, devise) => Solde = solde;

public void Crediter(double montant) => Solde += montant;


public void Debiter(double montant) => Solde -= montant;
public string Decrire() => "Le solde du compte de " + Titulaire + " est de " + Solde + " " + Devise;
Encapsulation
32
Particularité du C# 
class Program
{
static void Main(string[] args)
{
CompteBancaire comptePierre = new CompteBancaire("Pierre", "euros", 1000);
// utilisation des propriétés (accesseurs)
string nom = comptePierre.Titulaire; // en lecture (getter)
comptePierre.Solde = 500; // en écriture (setter)
comptePierre.Devise = "dollars"; // en écriture (setter)
System.Console.WriteLine(comptePierre.Decrire());
}
}
Encapsulation
Propriété en lecture seule 
33
 Comme son nom l’indique, c’est une propriété qui ne possède que le getter
 A l’inverse il existe aussi les propriétés en écriture seule (que le setter)
public class CompteBancaire
{
private double solde;
public double Solde

{
get
{
return solde;
}
}
public CompteBancaire(string titulaire, string devise)
{
solde = 0;
}
Encapsulation
Propriété en lecture seule 
34
class Program
{
static void Main(string[] args)
{
CompteBancaire comptePierre = new CompteBancaire("Pierre", "euros", 1000);
// utilisation des propriétés (accesseurs)
string nom = comptePierre.Titulaire; // en lecture (getter)
comptePierre.Solde = 500; // Erreur de compilation
comptePierre.Devise = "dollars"; // en écriture (setter)
System.Console.WriteLine(comptePierre.Decrire());
}
}
Encapsulation
Propriété en lecture seule 
35
public class CompteBancaire
{
public string Titulaire { get; set; }
public double Solde { get; private set; }
public string Devise { get; set; }
public CompteBancaire(string titulaire, string devise)
{
Titulaire = titulaire;
Devise = devise;
Solde = 0;
}
Héritage
 
 L'héritage est l'un concept de la POO. Il permet de créer des classes à partir de classes existantes.
36
 L'héritage est un mécanisme objet qui consiste à définir une classe à partir d'une classe existante. Une classe héritant
d'une autre classe possède les caractéristiques de la classe initiale et peut définir ses propres éléments. C’est une relation
particulière qui existe entre deux classes.
 C’est une forme de généralisation ou de spécification d’une classe
 La classe qui est hérité est encore appelée classe mère, classe parente, classe de base, super classe et la classe qui
hérite est encore appelée classe fille, classe enfant, classe dérivée, sous classe
 En UML, cette relation est matérialisée par la une fèche vide dont l’extrémité pointe vers la classe mère
 En C# l’héritage multiple n’existe pas: en d’autres termes le langage permet à une classe d’hérité d’une et une seule
classe à la fois, contrairement aux langages comme le C++ ou le Python
 Supposons maintenant que nous ayons à gérer un nouveau type de compte : le compte épargne. Comme un compte
classique, un compte épargne possède un titulaire, un solde et une devise. Sa spécificité est qu'il permet d'appliquer des
intérêts à l'argent déposé sur le compte.
 Bien sûr, il serait possible de concevoir une classe CompteEpargne totalement distincte de la classe CompteBancaire.
Cependant, on constate qu'un compte épargne possède toutes les caractéristiques d'un compte bancaire plus des
caractéristiques spécifiques.
 La meilleure solution serait de faire hériter CompteEpargne par CompteBancaire : On dit que l'héritage créé une
relation de type ’’est un’’ entre les classes. Dans notre exemple, un compte épargne est un type particulier de compte
bancaire.
Héritage
Conception 
37
Héritage
Implémentation en C# 
38
public class CompteEpargne : CompteBancaire
{
private double tauxInteret;

public CompteEpargne(string leTitulaire, double soldeInitial, string laDevise, double


leTauxInteret) : base(leTitulaire, soldeInitial, laDevise)
// appel du constructeur de la classe CompteBancaire
// le mot-clé "base" permet d'accéder à la classe parente
{
tauxInteret = leTauxInteret;
}

// Calcule et ajoute les intérêts au solde du compte


public void AjouterInterets()
{
// ... (détaillé plus bas)
}
}
Héritage
Avantages 
39  Grâce à la relation d'héritage, un objet de la classe CompteEpargne peut utiliser les fonctionnalités de la classe
CompteBancaire sans avoir à les redéfinir. On peut donc débiter ou créditer un compte épargne exactement comme un
compte bancaire.
double tauxInteret = 0.05; // taux d'intérêt : 5%
CompteEpargne comptePaul = new CompteEpargne("paul", 100, "dollars", tauxInteret);
// appel des méthodes de CompteBancaire sur le compte épargne
comptePaul.Debiter(1000);
comptePaul.Crediter(1500);
Console.WriteLine(comptePaul.Decrire()); // Affiche 600 $
NB: Par contre, le calcul des intérêts (méthode AjouterInterets) ne peut se faire que sur un objet de la classe
CompteEpargne. L'héritage est une relation unidirectionnelle.
comptePaul.AjouterInterets(); // OK : comptePaul est un compte épargne
Console.WriteLine(comptePaul.Decrire());
CompteBancaire comptePierre = new CompteBancaire("pierre", 100, "dollars");
comptePierre.AjouterInterets(); // Erreur : comptePierre est un compte bancaire, pas un
compte épargne
 Grâce à l'héritage, il est possible de réutiliser les fonctionnalités d'une classe existante en la spécialisant. Il est également
possible de spécialiser une classe dérivée.
Héritage
Héritage et encapsulation 
40
 Si nous essayons d’implémenter la méthode AjouterInterets, on constate l’erreur suivante

 Dans cet exemple, la classe dérivée CompteEpargne tente d'accéder à l'attribut solde qui appartient à la
classe de base CompteBancaire. Cependant, cet attribut est défini avec le niveau de visibilité private !
Cela signifie qu'il n'est utilisable que dans la classe où il est défini, et non dans les classes dérivées.
 interdire l'accès à un membre d'une classe (attribut, propriété C# ou méthode) depuis l'extérieur tout en
permettant son utilisation par une classe dérivée, il faut associer à ce membre un niveau de visibilité
intermédiaire : protected.
Héritage
Héritage et encapsulation 
41
public class CompteBancaire
{
private string titulaire;
protected double solde; // attribut protégé
private string devise;
// ...
Héritage
Héritage et encapsulation 
42
public class CompteBancaire
{
private string titulaire;
private double solde;
private string devise;
// ...
public double Solde
{
get { return solde; } // accesseur public pour la lecture
protected set { solde = value; } // mutateur protégé pour la
modification
}
// public string Solde { get; protected set; } // Equivalent avec une
propriété automatique
// ...
Héritage
Héritage et encapsulation 
43
public class CompteEpargne : CompteBancaire
{
// ...
public void AjouterInterets()
{
// utilisation du mutateur Solde pour accéder au solde du
compte
double interets = Solde * tauxInteret;
Solde += interets;
}
}
Polymorphisme
Principe 
44
 Afin de gagner en généricité, on peut appliquer le même code à des objets de types différents,
lorsque les classes de ces objets sont liées par héritage. C'est le principe du polymorphisme.
 Le polymorphisme est une conséquence de l’héritage et c’est le 4ième concept
de la POO
CompteBancaire compte1 = new CompteBancaire("Pierre", 300, "euros");
CompteEpargne compte2 = new CompteEpargne("Paul", 200, "dollars", 0.05);
CompteBancaire compte3 = new CompteBancaire("Jacques", 50, "euros");
CompteBancaire[] comptes = new CompteBancaire[] { compte1, compte2, compte3 };
foreach (CompteBancaire compte in comptes)
Console.WriteLine(compte.Decrire());
Polymorphisme
Polymorphisme de méthode 
45
 Il existe plusieurs types de polymorphisme: objet, méthode, interface,
etc.
 Mais le but est de permettre à des méthodes de même prototype
mais appartement à des classes différentes d’une hiérarchie
d’héritage de définir leur propre comportement.
 On peut imaginer que le méthode Decrire() d’un compte d’épargne
ne se fait pas de la même façon qu’un compte bancaire classique.
 On aimerait donc avoir une méthode Decrire() pour la classe
CompteEpargne sans perdre la notion de généricité vu
précédemment.
Polymorphisme
Polymorphisme de méthode  
46

 La méthode Decrire() de la classe fille masque la méthode Decrire() de la classe mère.


 Visual Studio signale cet avertissement en soulignant la méthode en vert
 On peut corriger cela en ajoutant le mot clé new après public
Polymorphisme
Polymorphisme de méthode  
47

public new string Decrire() => "Le solde du compte d'épargne de " + Titulaire + "
est de " + Solde + " " + Devise;
 Même si cette déclaration est suffisante elle ne garantie pas la généricité car le code vu
précédemment appellera toujours la méthode Decrire() de CompteBancaire
foreach (CompteBancaire compte in comptes)
Console.WriteLine(compte.Decrire());
 Pour résoudre ce problème il faudrait que la méthode Decrire() de la classe mère soit virtuelle.
 Pour cela en C#, il faudra rajouter le mot clé virtual après public de la méthode Decrire() de
la classe mère, ensuite rajouter override après public de la méthode Decrire() de la classe fille
 On parle alors de méthodes redéfinissables et de méthodes redéfinies
Polymorphisme
Polymorphisme de méthode  
48

public class CompteBancaire


{
//...
public virtual string Decrire() => "Le solde du compte de " + Titulaire + " est
de " + Solde + " " + Devise;
//...
}

public class CompteEpargne : CompteBancaire


{
//...
public override string Decrire() => "Le solde du compte d'épargne de " +
Titulaire + " est de " + Solde + " " + Devise;
//...
}
Polymorphisme
la classe object 
49
 Toute classe hérite implicitement de object
 Cette classe propose des méthodes redéfinissables (virtuelles)
telles que:
 string ToString()
 bool Equals(object obj) et int GetHashCode()
Polymorphisme
la classe object 
50
 ToString()permet de retourner les informations de l’objet comme pour un type valeur. C’est cette méthode
qui est invoquée pour une conversion implicite. Par défaut, son implémentation dans la classe object
retourne le nom complet de la classe de l’objet namespace.class
Console.WriteLine(compte.ToString()); //retourne POO.CompteBancaire
public class CompteBancaire
{
// ...
public override string ToString()
{
return "Le solde du compte de " + titulaire + " est de " + solde + " " + devise;
}
}
public class CompteEpargne : CompteBancaire
{
public override string ToString() => "Le solde du compte d'épargne de " + Titulaire + "
est de " + Solde + " " + Devise;
}
Console.WriteLine(compte); //Console.WriteLine(compte.ToString())
 Plus besoin de la méthode Decrire()
Polymorphisme
la classe object 
51
 Equals() et GetHashCode() permettent de définir une ou plusieurs propriétés afin de savoir si deux
objets de la classe ou de la même hiérarchie de classes sont égaux. Par défaut, son implémentation
dans la classe object compare les objets par leur adresse mémoire comme le ferait l’opérateur
==
 Rappel: les objets en POO sont en réalités des références d’objet
CompteBancaire compte1 = new CompteBancaire("Pierre", 300, "euros");
CompteBancaire compte2 = new CompteBancaire("Pierre", 300, "euros");
Console.WriteLine(compte1 == compte2);
//Résultat : false
Console.WriteLine(compte1.Equals(compte2));
//Résultat : false
 On peut donc choisir une ou deux propriétés pour former la clé de comparaison d’un compte
bancaire ou en créer une. Pour notre exemple on ajouter une propriété NumeroCompte
Polymorphisme
la classe object 
52
public class CompteBancaire
{
public string NumeroCompte { get; private set; }
//…
public override int GetHashCode()
{
return NumeroCompte.GetHashCode();
}
public override bool Equals(object obj)
{
var compte = obj as CompteBancaire; //as converti ou renvoie
null
return NumeroCompte.Equals(compte?.NumeroCompte);
}
}
Polymorphisme
la classe object 
53
public class CompteBancaire
{
public string NumeroCompte { get; private set; }
public string Titulaire { get; set; }
public double Solde { get; private set; }
public string Devise { get; set; }
public CompteBancaire(string titulaire, string devise)
{
Titulaire = titulaire;
Devise = devise;
Solde = 0;
}
public CompteBancaire(string titulaire, string devise, double solde) :
this(titulaire, devise) => Solde = solde;
public void Crediter(double montant) => Solde += montant;
public void Debiter(double montant) => Solde -= montant;
public override string ToString() => "Le solde du compte de " + Titulaire + " est de
" + Solde + " " + Devise;
public override int GetHashCode() => NumeroCompte.GetHashCode();
public override bool Equals(object obj) => obj is CompteBancaire bancaire &&
NumeroCompte.Equals(bancaire?.NumeroCompte); //is converti comme TryParse

}
Polymorphisme
la classe object 
54

CompteBancaire compte1 = new CompteBancaire("12345E",


"Pierre", 300, "euros");
CompteBancaire compte2 = new CompteBancaire("12345E",
"Pierre", 300, "euros");
Console.WriteLine(compte1 == compte2);
//Résultat : false
Console.WriteLine(compte1.Equals(compte2));
//Résultat : true
 Afin que l’opérateur == puisse faire aussi une comparaison avec un attribut ou
une propriété, il faudrait le redéfinir (surcharger) également. Mais ceci est une
autre histoire que je ne vous raconterai pas 😏!
Classe abstraite
Définition 
55

 C’est une classe qui ne peut être instancié et donc vouée à l’héritage
 Une classe abstraite peut contenir des méthodes abstraites et concrètes
 En C#, elle est définie avec le mot clé abstract avant class
 Imaginons ces cas de figure:
 un compte bancaire est soit un compte courant, soit un compte épargne.
 un compte courant se caractérise par le numéro de la compte bancaire qui lui est associée, ainsi que
par un découvert maximal autorisé. Tout retrait qui ferait passer le nouveau solde en dessous du
découvert maximal est interdit et non effectué.
 on ne peut retirer en une seule fois plus de la moitié du solde d'un compte épargne.
Classe abstraite
Conception 
56
Classe abstraite
Méthode abstraite 
57
 C’est une méthode qui n’a pas d’implémentation, juste son prototype.
 C’est un contrat obligatoire que toute classe qui en héritera devra remplir en fournissant une implémentation.

 Les méthodes abstraites, comme les méthodes virtuelles sont redéfinissables (override)
 En C#, elle est définie avec le mot clé abstract après public
 Dans notre exemple la méthode débit n’a plus ce comportement générique qui consistait uniquement à retirer un montant du compte. Son
implémentation dépend du type de compte.
 Cette méthode ne peut donc pas être virtuelle puisque son implémentation est abstraite

public abstract class CompteBancaire


{
//...
// La méthode Debiter est maintenant abstraite
public abstract void Debiter(double montant);
//...
}
Classe abstraite
Méthode abstraite 
58
public class CompteCourant : CompteBancaire
{
// …
// Redéfinition de la méthode Debiter
public override void Debiter(double montant)
{
// on n'effectue le débit que si le solde
final reste supérieur au découvert
if (Solde - montant >= decouvertMaxi)
Solde -= montant;
}
}
Classe abstraite
Méthode abstraite 
59

public class CompteEpargne : CompteBancaire


{
// ...
// Redéfinition de la méthode Debiter
public override void Debiter(double montant)
{
// Le montant maximal d'un retrait est la
moitié du solde actuel
if (montant <= Solde / 2)
Solde -= montant;
}
}
Classe abstraite
Méthode abstraite 
60

 Pour empêcher l’héritage d’une classe on utilise le mot clé


sealed
 Il est en de même pour empêcher la redéfinition d’une méthode
Interface
Définition 
61

 Les interfaces sont utilisées avec des classes pour définir ce que
l’on appelle un contrat. Un contrat est un accord sur ce que la
classe fournira à une application.
 Une interface déclare les propriétés et les méthodes. Ensuite la
classe définit exactement ce que fera la méthode.
 En C#, une interface peut être définie à l’aide du mot
clé interface. Les interfaces peuvent contenir des méthodes, des
propriétés, des indexeurs et des événements en tant que
membres.
Interface
Exemple 
62

interface MyInterface
{
/* Toutes les méthodes sont publiques par défaut
* Et ils n'ont pas de corps
*/
void method1();
void method2();
}
Interface
Implémentation 
63 using System;
public interface A
{
void method1();
void method2();
}
class B : A
{
public void method1()
{
Console.WriteLine("La méthode 1 est implémentée");
}

public void method2()


{
Console.WriteLine("La méthode 2 est implémentée");
}
}
public class Program
{
public static void Main(string[] args)
{
B b = new B();
b.method1();
}
}
Interface
Interface vs Classe abstraite 
64
 L’interface ne possède que les méthodes abstraites.
 La classe abstraite peut contenir des méthodes concrètes.
 Si nous voulons une implémentation qui sera la même pour toutes les classes
filles, il vaut mieux opter pour une classe abstraite plutôt que pour une interface.
 Avec une interface, nous pouvons laisser l’implémentation pour les classes qui
vont implémenter l’interface.
 Avec une classe abstraite, nous pouvons partager l’implémentation de toutes les
classes filles dans un emplacement central et éviter ainsi la duplication de code
dans les classes filles.
 Avec une classe abstraite, nous pouvons partager l’implémentation de toutes les
classes filles dans un emplacement central et éviter ainsi la duplication de code
dans les classes filles.
Interface
Interface et héritage 
65
 Une interface peut hériter d’une autre interface, tout comme les classes peuvent hériter d’autres classes.
Une classe implémentant une interface qui hérite de plusieurs interfaces doit implémenter toutes les
méthodes de l’interface et de ses interfaces parent.

interface A { }
interface B : A { }

class C : B
{
//Implémenter tous les membres de A et B.
}
Interface
Interface et polymorphisme
66
 Vous ne pouvez pas créer une instance d’interface, mais vous pouvez créer des objets de classe et les
assignés à une variable de type interface

interface A { }

class B : A
{
//Implémenter les membres de A.
}

A a1 = new B();
Interface
Interface et implémentation
67
 Une classe peut implémenter plusieurs interfaces et doit définir tous les membres de toutes les
interfaces.

interface A { }
interface B { }
interface C { }

class D : A, B, C
{
//Implémenter tous les membres de A, B et C.
}
References
68
https://docs.microsoft.com/fr-fr/dotnet/csharp/programming-guide/inside-a-progr
am/coding-conventions
FIN
69

Questions

Vous aimerez peut-être aussi