# Programmation Perl/Orienté Objet
## Introduction

Cette page sera écrite en deux parties distinctes : la définition de la programmation orientée objet en faisant abstraction d'un langage en particulier, puis comment l'utiliser dans le langage étudié.
Gardez à l'esprit que le concept de programmation orientée objet est simple, il y a juste quelques mots de jargon à connaître.

### Ce qu'est la programmation orientée objet

La programmation orientée objet est une manière de concevoir une application. La page wikipedia à ce sujet est bien faite, mais faisons un petit résumé pratique (et plus clair).
La POO se base sur quelques notions assez simples (rappelons que le but est de simplifier la programmation).

#### Les objets et leur classe

Un objet est un ensemble d'attributs (variables) et de méthodes (fonctions). Une voiture par exemple pourrait se représenter par un objet « Voiture ». Elle est composée de quatre roues, un volant, quatre sièges… qui représentent autant d'attributs de l'objet. La voiture peut également se démarrer, rouler, tourner, s'arrêter… qui représentent les méthodes possibles pour cet objet.
Dans la plupart des langages, pour créer un objet et le définir, nous créons une classe (un fichier avec les différents attributs et méthodes de l'objet). À partir de cette classe, nous pouvons créer des instances. Ainsi, nous pouvons avoir autant de voitures que nous le souhaitons, qui possèdent toutes les mêmes attributs (pas forcément de même valeur cependant) et les mêmes méthodes, à partir de la classe voiture. Exemple : la classe voiture possède un attribut « couleur » et des méthodes (rouler, tourner…), nous créons deux instances de la classe voiture, une avec l'attribut « couleur » à « rouge » et l'autre à « bleue ». Les voitures sont indépendantes.

#### Le typage et le polymorphisme

Chaque objet est un type différent (le type est le nom de sa classe). Il définit ses propres attributs et ses méthodes, et il est utile d'un point de vue sémantique dans notre code. Prenons par exemple la gestion d'un parking, on va faire entrer des « Voitures » dans ce parking, pas des entiers ou une chaîne de caractères. C'est donc une structure de données qui a un but sémantique.

#### Héritage et redéfinition

Pour simplifier l'écriture de code (et en écrire moins), on a créé le principe d'héritage. Prenons un exemple simple : nous souhaitons gérer un jeu de courses de voitures. Nous possédons une trentaines de modèles de voitures différentes (quelques particularités qui changent), cependant elles ont toutes quatre roues, des portières etc. Pour simplifier l'écriture du code, nous allons définir ce qu'est une voiture, et dire que les différents modèles « héritent » de la classe « voiture ». Ainsi, tous les modèles possèdent de base les attributs qu'ils ont en commun, sans avoir à le dire explicitement dans chaque classe. On vient donc de factoriser grandement notre code.

## Perl et la POO

Perl a connu plusieurs implémentations de programmation orientée objet via différents modules. Afin d'harmoniser les pratiques, Perl6 reprend le concept de POO dans sa syntaxe de base, et ceci a été repris dans Perl5 par le module Moose. Nous allons voir comment programmer en orienté objet avec cette bibliothèque, qui s'avère de nos jours être la bonne manière de coder en POO en Perl.

### Bases de POO en Perl
#### Créer une instance : new

Chaque package possède implicitement une méthode particulière (souvent appelée « new ») pour créer une instance de la classe. Nous appelons les méthodes d'un objet via l'opérateur « -> ».
$objet est maintenant une référence à un objet « Voiture ».

#### Créer et appeler une méthode : sub et ->

Une méthode est une simple fonction comme nous avons déjà vu dans un chapitre précédent. Le premier paramètre est une référence à l'objet courant. Cette méthode est définie dans un « package », qui sera notre classe. Nous verrons plus loin comment créer une classe, pour voir directement la bonne manière de faire (via Moose).
Comme nous l'avons vu précédemment avec « new », pour appeler une méthode il suffit d'utiliser l'opérateur « -> ».
À remarquer : au début on utilise l'opérateur « -> » sur le package directement pour créer l'instance, après on l'utilise sur l'objet référençant l'instance pour faire appel aux méthodes liées à un objet en particulier (que l'on nomme méthodes d'instance).

### POO via Moose

Nous arrivons à la partie la plus intéressante. Jusque-là tout était peut-être un peu flou, mais cela va s'éclaircir !

#### Créer une classe

Une classe se définit par un package, l'utilisation de Moose et se termine par « 1; » tout à la fin du fichier.
Difficile de faire plus simple non ? Cette classe ne contient rien de bien utile pour le moment, on ne peut que créer une instance de l'objet comme vu précédemment.

#### Les attributs
##### Bases : has is isa required

Un attribut est déclaré avec le mot clé has. On doit lui passer au moins un paramètre : l'option « is » qui définit si l'attribut est en lecture seule (ro pour read-only) ou s'il est en lecture et écriture (rw pour read-write).
Les attributs peuvent avoir un type précis, qui se trouve dans [liste]. Nous forçons à vérifier ce type avec l'option isa.
Nous pouvons même créer de nouveaux types mais cela va au delà du but de ce livre, veuillez vous référer à la documentation officielle du module MooseUtilTypeConstraint.
Nous pouvons décider qu'une option est obligatoire.
Il y a d'autres options disponibles dont de très intéressantes et puissantes à découvrir dans la documentation du module, que j'encourage vivement à aller voir pour les anglophones.

##### Déclarer plusieurs attributs directement

Petite astuce pour gagner du temps, déclarer plusieurs attributs avec les mêmes options.

##### Créer l'instance en modifiant la valeur des attributs

On peut choisir de modifier la valeur d'un attribut dès la création de l'instance de la classe.

##### Récupérer et modifier la valeur d'un attribut

Pour récupérer ou modifier un attribut, il faut passer par des fonctions nommées accesseurs. Pour récupérer la valeur d'un attribut il suffit d'écrire $objet->nom_attribut et pour la modifier $objet->nom_attribut("nouvelle valeur").

##### Modifier les noms des accesseurs

Il est possible de modifier les fonctions d'accès et de modification des attributs. Cela se fait grâce aux options reader et writer de la création d'un attribut.
Une convention veut que nous nous précédions le nom de l'accesseur par un underscore ( _ ) lorsque nous ne voulons pas que les classes filles l'utilisent. Rien n'empêche en pratique leur utilisation, mais cela est à utiliser à vos risques.

##### Déclencheur sur la modification d'un attribut : trigger

Lors la modification d'un attribut on veut avoir une fonction qui soit appelée.
Soit le fichier Personnage.pm :
Soit le fichier Jeu.pl :

##### Références faibles : weak_ref

Tout d'abord, petit point sur la façon dont Perl gère la mémoire.
En Perl, nous ne manipulons pas directement la mémoire de l'ordinateur, la gestion est déléguée directement à Perl. Quand on n'utilise plus une variable, ou un objet, il faut « libérer » la zone mémoire qu'elle occupe. Pour trouver ce qu'il faut libérer, on utilise un ramasse-miettes (Garbage Collector). Il y a différentes manières d'implémenter un ramasse-miettes, celle utilisée par Perl est le comptage de références.
Le principe est assez simple : pour chaque variable on va compter le nombre de fois qu'on a une référence qui pointe dessus, une fois qu'on n'en a plus, on ne peut plus accéder à cette zone mémoire. Par conséquent, on peut libérer la mémoire puisque la variable n’est de toutes manières plus utilisable. Pour plus d'informations, je conseille d'aller voir la page sur les ramasse-miettes sur wikipedia.
Soit le module Personnage tel que :
Soit le code utilisant ce module :

#### Héritage : extends

Comme nous avons vu en introduction de ce chapitre, l'héritage permet de créer des classes décrivant toujours un objet plus précis. Par exemple, pour un jeu vidéo on fait une classe "Personnage" puis une classe "Magicien". Un magicien est un personnage. Il hérite donc de toutes ses propriétés et en rajoute potentiellement.
Soit le module Personnage tel que :
Maintenant on veut créer le magicien qui, en plus d'avoir un nom, pourra lancer une boule de feu. Soit le module Magicien :
Maintenant on essaie notre classe :
Perl permet l'héritage multiple, ce qui veut dire qu'une classe peut hériter de plusieurs autres classes, voici la syntaxe :

##### Modifier une méthode héritée (surcharge)

Lors d'un héritage, on souhaite parfois changer une méthode dont on hérite, cela s'appelle une surcharge. Pour cela nous n'avons qu'à recréer une méthode de même nom qui remplacera l'ancienne.

##### Modifier un attribut hérité : +

On souhaite parfois changer une option de l'attribut, comme par exemple rendre un attribut non modifiable (ro) ou donner une valeur par défaut à un attribut, pour cela on peut modifier la définition de l'attribut. Cela se fait simplement en rajoutant un "+" devant le nom de l'attribut dans notre classe fille (celle qui hérite).
Attention cependant, il est déconseillé de redéfinir un attribut juste pour changer sa valeur par défaut, on préfèrera donner une valeur par défaut à un attribut dans le constructeur de la classe.

#### Les rôles : Moose::Role with requires

Un rôle n'est pas à proprement parler une classe, mais plutôt une alternative à la hiérarchie imposée par la programmation orientée objet. Si nous reprenons des exemples déjà vus : un magicien est un personnage. Un magicien peut aussi être un guérisseur (qui soigne les autres personnages) mais ce n'est pas nécessairement le cas. On peut dire qu'il remplit la fonction de guérisseur, il a ce rôle.
Un rôle est défini comme une classe, avec éventuellement des attributs et des méthodes et utilise Moose::Role en lieu et place de Moose. Ce que nous allons faire généralement avec les rôles c'est de les utiliser pour indiquer des fonctions qui doivent apparaître dans la classe qui a ce rôle. Pour cela nous utilisons le mot clé "requires".
Soit le rôle Guerisseur :
Notre classe Magicien :
Maintenant faisons un essai sur notre code :
Un rôle ne peut pas être instancié. Si on créer des méthodes ou qu'on défini des attributs dans le rôle, alors les classes qui ont ce rôle auront aussi ces attributs et ces méthodes, comme en cas d'héritage.