Vous êtes sur la page 1sur 6

C# - La POO facile - Support de cours © Gamecodeur

Atelier Programmation Orientée Objet


Langage : C#
Framework : Tous les frameworks C#

Introduction
La POO est un concept qui permet de transposer, en programmation, des notions issues du monde réel.

En POO vous créez des ​classes ​qui décrivent des o ​ bjets​. Ces classes comportent des données
(​membres​) et du code (​méthodes​) qui lui permet d'agir sur ces données, ou avec des données provenant
de l'extérieur.

Pour mieux illustrer le concept, un exemple issu du monde réel :

Un ​véhicule ​est un objet que l'on pourrait décrire avec une classe, comportant le nombre de places et la
vitesse maximale. Ses actions possibles seraient d'avancer (à une vitesse qu'on lui transmettrait) et de
freiner. Le fait d'avancer ferait alors évoluer sa vitesse actuelle.

Classe : "véhicule".
Membres : Nombre de places, vitesse maximale, vitesse actuelle.
Méthodes : Avancer(vitesse), Freiner.

Imaginons maintenant que vous souhaitiez manipuler plusieurs types de véhicules ! Vous allez alors utiliser
la notion d'héritage. Hériter consiste à réutiliser, étendre ou modifier le comportement d'une autre classe.

Exemples : un camion, une voiture, seraient des "véhicules". Ces classes héritent donc de la capacité de
gérer leur nombre de places, leur vitesse maximale, leur vitesse actuelle, d'avancer et de freiner… Mais
elles peuvent étendre la classe véhicule pour par exemple gérer une remorque (pour le camion). Leur
nombre de places et leur vitesse maximale sera également différente !

Grâce à ce modèle, on pourrait alors gérer des listes de "véhicules", qui seraient soit des voitures, soit des
camions…

Et dans un jeu vidéo ? ​Dans un jeu vidéo, nos objets seront des sprites, qui seront soient des éléments
de décor, des ennemis, le héro lui même ! Chacun partageant des propriétés communes, mais chacun
ayant des comportements différent et des spécificité.

C'est ça la POO !
Héritage
Permet de créer des classes qui réutilisent, étendent ou modifient le comportement d'une autre classe.

Par exemple, dans le cadre d'un RPG, la classe de base serait "Personnage", dont on pourrait hériter pour
créer des "Barbares", "Druides", etc. qui auraient des comportements spécifiques. Par exemple le dé utilisé
pour déterminer le nombre de Points De Vies d'un Barbare n'est pas le même que celui utilisé pour un
Druide. Pourtant, les deux partagent la priopriété "Points De Vies".

Vocabulaire :
On dit qu'une classe "​hérite​" d'une autre classe. Elle vient une classe "​dérivée​" (ou "​classe fille​"). La
classe dont elle dérive est la "​classe parente​" ou "​classe de base​".

Dans ce schéma : la classe parente est "Personnage" et les classes dérivées sont "Barbare", "Druide", etc.
On constate que chaque classe fille possède une valeur différente pour les Points De Vie (PDV).

Rappel :
Accessibilité :
public : aucune restriction, tout le monde à accès.
protected : accessible à la classe, et aux classes dérivées
private : accessible à la classe seulement

On aurait donc une classe de base :

class Personnage
{
public string Nom;
public int TotalPointsDeVie;
protected string DéPointDeVie;

public Personnage(string pNom)


{
// Par défaut, aucun dé de points de vie.
DéPointDeVie = "";
Nom = pNom;
}
}
et des classe dérivées :

class Barbare : Personnage


{
public Barbare(string pNom) : base(pNom)
{
DéPDV = "1D12";
}
}

class Magicien : Personnage


{
public void LanceUnSort(string pNomDuSort);
public Barbare(string pNom) : base(pNom)
{
DéPDV = "1D12";
}
}

Dans cet exemple, le constructeur de la classe parente est appelé au moment de l'appel du constructeur
de la classe dérivée. Ce rôle est rempli pas l'appel de "base(pNom)" à la suite de la déclaration du
constructeur de la classe fille.

Notez que le Druide étend les capacités de base d'un personnage en proposant, en plus, de Lancer un sort
de magie.

Les propriétés (Properties)


Il faut éviter d'utiliser des membres publics dans une classe. C'est mal. Cela ne respecte pas un des 4 lois
de la POO : l'encapsulation (voir plus bas).

C# propose donc les propriétés :

private string monNom;


public string Nom
{
get
{
return Nom;
}
private set
{
// Ici un code pour vérifier la valeur avant de l'affecter
if (....)
{
monNom = value;
}
}
}

Elles offrent 2 avantages principaux :


- Elles permettent, si on le souhaite un jour, d'ajouter un traitement spécifique au moment de l'accès
ou de la modification d'un membre de la classe
- Elles permettent de changer facilement l'accessibilité d'un membre dans un sens, ou dans les 2
(dans l'exemple, monNom ne pas être modifié de l'extérieur)

Mais aussi :
- Elles permettent de poser un "point d'arrêt" pour déboguer votre code au moment où un membre
est lu ou modifié.

Pourtant, dans de nombreux cas, on n'a pas non plus envie (ou besoin) de coder une méthode pour
modifier un membre, et une autre pour en récupérer la valeur… Vu qu'on a besoin des 2 possibilités et
qu'on n'a aucun traitement spécifique à réaliser pendant l'opération.

C# a pour cela introduit un concept simple : les propriétés automatiques :

public string monNom {get; set;}

Autre exemple :

public string monNom {get; private set;}

Dans ce cas on peut plus lire monNom depuis l'extérieur, mais on ne peut pas le modifier.

Classes et méthodes abstraites


Dans notre exemple de classe Personnage, il n'y a aucune utilisé à créer une instance de Personnage
maintenant que nous avons déclaré les classes filles. Notre jeu de rôle n'utilisera que des,instances de
"Barbare", "Guerrier", etc. et jamais des instance de "Personnage".

Pour le spécifier au compilateur (et pas là même aux programmeurs qui utiliseraient votre code), nous
allons déclarer Personnage comme classe abstraite :

abstract class Personnage


{
...

Dorénavant, si l'on essaye de créer une instance de Personnage (new Personnage…) le compilateur
refusera.

On peut aussi obliger une méthode d'être implémentée dans la classe dérivée (par exemple pour ne pas
oublier de le faire, sinon le compilateur affiche une erreur !). A faire dans la classe de base :

public abstract void Attaque();

Avec ceci, les classes dérivées (Barbare, Guerrier, etc.) devront obligatoirement implémenter (coder !) la
méthode Attaque sinon le programme ne compilera pas.

Pour la coder, il faudra préciser au compilateur qu'on "redéfinie" la méthode abstraite, à l'aide du mot clé
"override". Le compilateur s'assure ainsi que vous appelez votre méthode du même nom que la méthode
abstraite pas choix et non par erreur (homonymie) :
public override void Attaque()
{
Console.WriteLine("Je suis un druide et j'attaque !");
}

Les méthodes virtuelles


Un concept fabuleux pourtant incompris et considéré comme difficile à comprendre par de nombreux
programmeurs débutants !
Grâce aux méthodes virtuelle, vos objets pourront avoir plusieurs comportements (polymorphisme), en
fonction de leur type. Si on demande à un personnage de parler par exemple, un Druide ne parlera pas de
la même manière qu'un Barbare. Pourtant tous les deux sont doués de parole.

En rendant la méthode "Parler" virtuelle dans les classes dérivées de Personnage, on permet à votre
programme de manipuler des "Personnages" et d'utiliser la bonne version de la méthode en fonction du
type de personnage ! On parle de "​substitution​". La méthode Parler d'un Druide se substitue à la méthode
parler de la classe de base Personnage.

Grâce aux méthodes virtuelles, vous pouvez manipuler des listes de Personnages, qui pourront être des
Druide ou des Barbares. Et au moment de l'exécution, si vous demandez à un personnage de parler, le
programme décidera d'appeler la méthode Parler de la bonne classe dérivée.

Autre exemple : des formes. Regardez cet exemple qui est tout aussi parlant :

Classe de base : Formes


Classes dérivées : Cercle, Carré, Triangle.
Méthode : Dessiner.

En rendant la méthode Dessiner virtuelle, on pourra manipuler des listes de "Formes", qui pourront être de
type "Cercle", "Carré" ou "Triangle". Et au moment de dessiner chacune des formes, le programme
appellera la méthode "Dessiner" soit du "Cercle", soit du "Carré", soit du "Rectangle"...

Si on n'avait pas rendu la méthode abstraite, le programme aurait appelé la méthode "Dessiner" de la
classe "Forme" !

Note : une propriété peut aussi être virtuelle.

La redéfinition
Lorsqu'on commence à manipuler des objets dérivés, on a souvent besoin d'avoir un comportement "de
base" dans la classe de base. On peut pour cela partager le code de la classe de base avec la classe
dérivée.

Il suffit d'appeler le code de la méthode d'origine, dans la classe parente. Pour cela on accède à la classe
parente grâce à au mot clé "​base​" qui fourni un accès à la classe parente. On a déjà utilisé ce mot clé
pour le constructeur.

Pour appeler la méthode de la classe de base, on fait donc :

public override void Parler()


{
// Votre code avant l'appel
base.Parler();
// Votre code après l'appel
}

Les 4 notions clés de la POO


Allez, un peu de vocabulaire savant…
Maintenant que vous avez mis en pratique, ces concepts un peu "abstraits" vont vous paraitre plus clair.

Abstraction
L'abstraction, c'est l'idée de généraliser des comportements au sein d'un concept abstrait. Par exemple, un
appareil est un concept abstrait. Cela peut être un téléphone, un ordinateur, etc. C'est un concept, que
vous mettez en pratique pour déterminer quelles sont les classes dont vous avez besoin, leur
comportement, leur hiérarchie...

Encapsulation
L'encapsulation consiste à cacher les détails de l'implémentation (ce qui se passe à l'intérieur). Par
exemple, tous les appareils ont une prise électrique. Vous pouvez brancher l'appareil pour le mettre en
route mais vous n'avez pas besoin de savoir ce qui se passe à l'intérieur de l'appareil pour qu'il se mette en
route.

On peut lier abstraction et encapsulation ainsi :


La notion de smartphone est une ​abstraction​, dans laquelle certaines fonctionnalités et services sont
encapsulés​.

Héritage (en anglais : Inheritance)


Là c'est beaucoup plus simple...
C'est le mécanisme qui permet à un objet d'utiliser, étendre ou modifier les propriétés d'un autre objet.
Par exemple, un ​Druide étend les propriété d'un P
​ ersonnage.

Polymorphisme
Le polymorphisme consiste à se comporter différemment, notamment en fonction de son type.
On peut aussi traduire Polymorphisme par : plusieurs (poly) / formes (morph).
Cela peut s'appliquer à une méthode ou à un objet.

Par exemple, une méthode peut avoir plusieurs implémentations, en fonction des paramètres qu'elle reçoit.
C'est la ​surcharge​. On parle de ​polymorphisme statique​ car on sait déjà, au moment de la compilation,
quelle version de la méthode va être utilisée.

Dans un deuxième cas, un objet pourra avoir un comportement différent en fonction de son type. C'est la
redéfinition​. Dans le cas de deux types de véhicule : une voiture et un vélo. Les deux ont la possibilité
d'avancer, mais l'un en actionnant un moteur, l'autre des pédales. Lorsque le programme va demander au
véhicule d'avancer, il appellera la bonne méthode (celle de la classe Voiture ou celle de la classe Velo) en
fonction du type réel de l'objet. On parle de ​polymorphisme dynamique​.

Vous aimerez peut-être aussi