Cours de Rémi JarjatCours de Rémi Jarjat
  • Liste des cours
  • Culture numérique
  • Git
    • Terminologie
    • Avant de commencer
    • Créer un dépôt (local)
    • Enregistrer des changements
    • Des branches
    • Mise en commun du travail
    • Annuler des changements
    • Réécrire l'historique
    • Des outils pour se simplifier Git
    • Exercices
    • Exemples pratiques
  • Linux
    • Installation
    • Historique
    • Rangement des fichiers
    • Les processus
    • Commandes de base
    • Commandes avancées
    • /linux/6-other-technologies.html
    • Exercices
    • Correction des exercices
  • PHP
    • Environnement de travail
    • Bases du PHP
    • Tests et boucles
    • Procédures et fonctions
    • Interagir avec l'utilisateur
    • La temporisation de sortie
    • PHP Doc et PSR
    • PHP Orienté objet
    • Héritage et objets
    • Factorisation
    • Manipuler la BdD avec PDO (PHP Data Object)
    • Architecture MVC
    • Webservices REST
    • Exercices - Bases
    • Exercices - Séparer en plusieurs fichiers
    • Exercices - POST et SESSION
    • Exercices - Panier et validation
    • Exercices - Objets
    • Exercices - BdD avec PDO
    • Projet - montage d'ordinateurs
    • Projet - Personnages de Jeux de Rôle
  • Symfony
    • Installer Symfony et son environnement de travail
    • Structure et utilisation d'un projet
    • Le routing
    • Les controllers
    • Twig
    • Les services et l'injection de dépendances
    • Doctrine et la BdD
    • Formulaires
    • Les traductions
    • Event listeners/subscribers
    • Connexion et sécurisation
    • Bundles
    • Easy Admin Bundle
    • API Platform
    • Pense-bêtes
    • Symfony au quotidien
    • Travailler avec Docker
    • Projet : annonces de SPA / éleveurs
    • Exercices
  • Javascript
    • Les bases du langage
    • Manipulation logique
    • Le DOM
    • JQuery
    • Ajax
    • Programmation orientée objet
    • Webpack
    • Outils utiles
    • Révisions
  • Serveur Lamp
  • Déploiement
    • Des outils et manières de faire
    • Déploiement par FTP
    • Wordpress
    • Intégrer Git dans le processus
    • GitHub Pages pour déployer facilement
    • Symfony et Angular
  • Docker
  • Intégration continue
  • Sécurité informatique

Programmation orientée objet

Jusqu'ici, nous avons codé nos programmes de manière procédurale. C'est-à-dire que le code se trouve dans l'ordre de son exécution (le code est exécuté ligne par ligne). En POO (Programmation Orientée Objet), tout s'articule autour de la notions d'objets : des éléments indépendants ayant leurs caractéristiques (appelées propriétés) et leurs fonctionnalités ( appelées méthodes).

Pourquoi la POO ?

La programmation orientée objet permet plusieurs choses :

  • une plus grande flexibilité du code (modifier une classe permet de modifier le comportement de tous les objets d'un coup)
  • une meilleure lisibilité (un objet regroupe toutes les caractéristiques et les fonctionnalités dont il a besoin)
  • une meilleure maintenabilité (pas besoin de copier-coller des éléments à plusieurs endroits du code et la logique est plus facile à retrouver)

Mise en pratique

Dans certains exercices de ce cours, j'ai utilisé ce qu'on appelle des objets littéraux. Un exemple d'objet littéral, qui va nous servir d'exemple pour la suite :

let player = {
    hp: 10, // On a ici une propriété de notre objet
    name: 'Dreeckan',
    strength: 5,
    defense: 10,
    isAlive: function () { // Et ici une méthode
        return this.hp > 0;
    }
};

Créer une classe et des objets

Maintenant, si nous voulons créer d'autres objets Player, basés sur le même modèle, nous pouvons créer une classe, un plan de fabrication pour des objets. Pour définir cette classe, commençons par l'essentiel : son nom. On l'écrit en PascalCase (c’est-à-dire sans espace entre les mots, avec une majuscule à chaque mot).

// Définition d'une classe
class Player {
    // Ici, nous ajouterons nos propriétés et méthodes
}

Une fois que nous avons notre classe, nous pouvons créer des objets (on parle d'instances de la classe Player) à partir de ce plan de fabrication. Pour le faire, nous allons utiliser le mot-clé new :

let player1 = new Player();
let player2 = new Player();

Constructeur et propriétés

Les propriétés sont les caractéristiques de notre objet. Dans le cas de notre Player, cela peut être :

  • ses points de vie,
  • son nom,
  • sa force,
  • sa défense,
  • toute autre caractéristique qui nous permettrait de le définir pour notre programme...

Nous pouvons définir ce qu'il se passe lors de l'appel de ce new et, si on le souhaite, lui donner des paramètres. Pour cela, nous ajoutons une méthode spéciale, le constructeur. Cette méthode est appelée automatiquement dès que l'on crée un nouvel objet avec new.

Attention, il ne faut pas confondre une propriété et une variable. Une propriété est toujours précédée d'un objet (ou de this) et ne peut être appelée sans.

// Un exemple de constructeur pour notre objet Player, sans paramètres

class Player {
    constructor() {
        // Ici this équivaut à demande l'objet Player en cours (celui qu'on a créé/instancié avec new)
        // On définit des propriétés et des valeurs par défaut
        // et on peut alors donner n'importe quelle valeurs à nos propriétés
        this.name = "";
        this.hp = 100;
        this.strength = 5;
        this.defense = 10;
    }
}

// Si on fait un new, sans paramètre, les propriétés sont bien définies et contiennent les valeurs demandées
let player1 = new Player();
// On peut accéder à une propriété de la même manière que nous l'avons vu avec les objets littéraux
console.log(player1); // Affiche Player {name: "", hp: 100, strength:5, defense: 10}

// On peut aussi accéder aux propriétés ou les modifier
player1.hp = 110;
console.log(player1.hp); // Affiche 110

Pour pouvoir créer un objet avec des valeurs, on donne des paramètres au constructeur :

// Un exemple de constructeur pour notre objet Player, avec des paramètres
// Les 3 derniers ont des valeurs par défaut 
// (si on ne leur donne pas de valeur, ils prennent leur valeur par défaut)

class Player {
    constructor(name, hp = 100, strength = 10, defense = 10) {
        // Attention à ne pas confondre this.name et name
        // La première est une propriété de l'objet Player qu'on instancie
        // La seconde est une variable : le paramètre du constructeur
        this.name = name;
        this.hp = hp;
        this.strength = strength;
        this.defense = defense;
    }
}

// Si on fait un new, sans paramètre, les propriétés sont bien définies et contiennent les valeurs demandées
let player2 = new Player('Test', 125, 11);
console.log(player2.name); // Affiche "Test"
console.log(player2.strength); // Affiche 11
// ...

Les méthodes

Les méthodes correspondent aux capacités ou aux actions que peut réaliser notre objet, c'est une fonction, dans une classe, même si elle ne porte pas le mot-clé function.

class Player {
    constructor(name, hp = 100, strength = 10, defense = 10) {
        this.name = name;
        this.hp = hp;
        this.strength = strength;
        this.defense = defense;
    }

    // Notre Player sait s'il est en vie. C'est utile à notre programme ;) .
    isAlive() {
        return this.hp > 0;
    }

    // Une méthode peut également avoir des paramètres, 
    // comme n'importe quelle fonction
    isStrongerThan(strengthToCompare) {
        return this.Strength > strengthToCompare;
    }

    // Une méthode nous permet de réaliser divers calculs,
    // et contenir la logique de notre objet.
    // Ici, on peut dire ce qu'il se passe quand notre joueur prend un coup
    takeHit(strength) {
        let damage = strength - this.defense;
        if (damage > 0) {
            this.hp -= damage;

            return damage;
        }

        return 0;
    }

    attack(otherPlayer) {
        // On peut utiliser les méthodes d'un autre objet Player, 
        // s'il est passé en paramètre
        let damageDealt = otherPlayer.takeHit(this.strength);

        return damageDealt;
    }
}

Un petit exemple de programme, utilisant notre objet Player précédent :

// Un premier joueur, avec toutes les valeurs par défaut
let player1 = new Player('Joueur1');
// Un second joueur, dont on définit les propriétés à l'aide du constructeur
let player2 = new Player('Joueur2', 125, 11, 5);

let damage = player1.attack(player2);
console.log(player1.name + ' inflige ' + damage + ' points de dégats à ' + player2.name);

Setters

Dans beaucoup de langages de programmation, vous entendrez parler de méthodes dites setters. Il s'agit de méthodes permettant de manipuler une propriété d'un objet. Idéalement, pour mettre à jour une propriété, il faut passer par un setter. L'intérêt est de pouvoir appliquer des traitements (mettre du texte en majuscule, modifier une autre propriété en même temps, etc.) dès que l'on souhaite mettre à jour la propriété.

class Player {
    constructor(hp = 100) {
        this.setHp(hp); // On appelle notre setter dès le constructeur
    }
    
    setHp(hp) {
        // Notre setter va nous permettre d'ajouter une vérification
        // Ici, notre joueur ne peut pas avoir plus de 100 points de vie
        if (hp > 100) {
            hp = 100;
        }
        this.hp = hp;
    }
}

Le mot-clé this

Dans les méthodes de vos classes, vous pouvez renvoyer la valeur de l'objet (l'instance) avec le mot-clé this. C'est ce que l'on fait dans le constructeur et différentes méthodes.

class Player {
    constructor(hp = 100) {
        // Ici this vaut l'objet en cours (peut être la valeur contenue dans player1 ou dans player2, par exemple)
        this.hp = hp; 
    }
}

let player1 = new Player();
let player2 = new Player();

⚠️ Attention toutefois au contexte des variables ! Dans une fonction anonyme, this va avoir une autre valeur.

class Test {
    constructor(tests = []) {
        tests.forEach(function(test) {
            this.something = test; // Ici, this ne correspond pas à notre objet !
        });
    }
}

Pour éviter ce problème :

class Test {
    constructor(tests = []) {
        tests.forEach(test => {
            this.something = test; // Avec une fonction fléchée, this correspond bien à notre objet
        });
        
        // Une autre solution : on déclare une variable intermédiaire qu'on utilisera dans la fonction
        let self = this;
        
        tests.forEach(function(test) {
            self.something = test; // On utilise notre variable intermédiaire pour contourner le problème
        });
        
        // Vous pouvez également utiliser .bind(), comme indiqué dans la première partie du cours ;)
    }
}

Exercices

Conception et utilisation de classes

Nous allons créer deux classes Book et Author pour représenter des livres et leurs auteurs.

Pour cet exercice, vous allez également avoir besoin de l'objet Date de Javascript, dont vous pourrez également trouver des exemples dans le cours.

Nous allons créer un fichier par classe : Book.js et Author.js. Ne pas oublier d'inclure ces deux fichiers dans votre HTML :

<script type="text/javascript" src="Book.js"></script>

Les propriétés d'un livre :

  • un ISBN (chaine de caractères)
  • un titre
  • un ou des auteurs (tableau d'objets Author)
  • une date de parution (objet Date)
  • un résumé (4ème de couverture)

Les propriétés d'un auteur :

  • un prénom
  • un nom
  • un ou des livres (tableau d'objets Book)
  • une date de naissance (objet Date)

Créer au moins 2 instances de chacun de ces objets (Si vous avez besoin d'inspiration)

Dernières mise à jour :
Prev
Ajax
Next
Webpack