PhiSyX / cfoulatech

Cours, exo, travaux pratiques
0 stars 0 forks source link

JS: Les classes #14

Open PhiSyX opened 1 day ago

PhiSyX commented 1 day ago

Maintenant que tu as vu comment fonctionne le type objet.

Laisse-moi te parler des classes. Entre avec moi dans le monde de la Programmation Orienté Objet (ou POO).

Les classes vont t'offrir une autre manière de concevoir des programmes dans une syntaxe plus organisée et plus structurée de ce que tu as pu voir jusqu'à présent.

Si ce sujet t'intéresse, alors, installe-toi et entre dans la danse et quant à moi, je te souhaite la bienvenue dans le monde de l'Orienté Objet.


Comme tu vas le voir, les classes ressemblent énormément au type objet que tu as vu dans le chapitre des objets. C'est totalement voulu car les deux sont liés. Mais sont un tantinet différents.

L'un représente une implémentation objet ou une sorte de plan (classe), et l'autre représente une valeur de type object en JavaScript (objet).

Une classe te permet d'obtenir une valeur JavaScript de type objet lors de sa construction. Chaque classe construite est une valeur de type objet indépendante avec des valeurs différentes.

Analyse de la syntaxe des classes

class CarteIdentité {
    date_de_naissance;
    prenom;
    nom;
    numero_carte;
    exemple_vide;

    couleur_carte = "violet";

    #code_pin;
    #code_puk;

    constructor(
        nom_utilisateur,
        prenom_utilisateur,
        date_de_naissance_utilisateur
    ) {
        this.date_de_naissance = date_de_naissance_utilisateur;
        this.prenom = prenom_utilisateur;
        this.nom = nom_utilisateur;
        this.numero_carte = this.#genere_numero_carte();
        this.#code_pin = this.#genere_code_pin();
        this.#code_puk = this.#genere_code_puk();
    }

    compare_code_pin(code_pin_utilisateur) {
        return this.#code_pin === code_pin_utilisateur;
    }

    #genere_code_pin() {
        return random_code(4);
    }

    #genere_code_puk() {
        return random_code(4);
    }

    #genere_numero_carte() {
        return random_number_card(24);
    }
}

Qu'est-ce qu'on observe ?

  1. Un nouveau mot-clé class, c'est par ça que l'on définit une classe.
  2. Un identifiant qui sert de nom.
  3. Des propriétés déclarées mais non initialisées.
  4. Des propriétés déclarées et initialisées.
  5. Des propriétés qui commencent par #
  6. Des méthodes qui prennent des paramètres ou non

Bien.

Tout d'abord, je vais commencer par parler de la méthode constructor. Cette méthode va être le point d'entrée de cette classe. C'est une méthode spéciale qui te permet de construire la classe en un nouvel objet. Dans l'exemple plus haut, le constructeur prend 3 paramètres (nom_utilisateur, prenom_utilisateur, date_de_naissance_utilisateur) et va affecter les propriétés nom, prenom, date_de_naissance en fonction de ces trois (3) paramètres. Pour construire cette classe, le langage introduit le mot-clé new, tu vas avoir besoin de son identifiant de classe pour ce faire. La construction se fait généralement en dehors de la classe.

let objet_instance = new CarteIdentité("S.", "Mike", "1991-12-07");

Le fait de construire avec new s'appelle créer une instance par convention de nommage. Une instance correspond à une valeur type objet et donc partage les mêmes points qu'un type objet.

Ce que je peux te dire sur le point 3) Des propriétés déclarées mais non initialisées.

Il s'agit des propriétés suivantes :

  1. date_de_naissance
  2. prenom
  3. nom
  4. numero_carte
  5. exemple_vide

Ces propriétés-là ont une valeur de type undefined par défaut.

Étant donné qu'il s'agit d'une implémentation, une sorte de "plan", tu NE PEUX PAS mettre directement les valeurs dans la classe, comme pour un type objet. Car ça voudrait dire que toutes les instances de ce plan auront ces valeurs-là. Ce n'est pas ce qu'on veut. On veut que chaque instance soit indépendante.

Lors de la construction, la méthode constructrice est appelée et va affecter des valeurs à ces propriétés en fonction de ses paramètres.

let objet_instance = new CarteIdentité("S.", "Mike", "1991-12-07");
alert(objet_instance.prenom); // Affiche "Mike"

En général toutes les propriétés sont affectées lors de la construction OU sont initialisées par défaut (Voir 4.), mais il se peut qu'une propriété n'ait pas de valeur dès lors la construction de classe. Mais ne t'inquiète pas, tu peux affecter une valeur "plus tard", c'est à dire, dans un endroit du code spécifique et non directement depuis le constructeur.

Par exemple :

let objet_instance = new CarteIdentité("S.", "Mike", "1991-12-07");
alert(objet_instance.exemple_vide); // Affiche undefined

// .. du code
// .. du code
// .. du code

objet_instance.exemple_vide = 42;
alert(objet_instance.exemple_vide); // Affiche 42

Ce que je peux te dire sur le point 4) Des propriétés déclarées et initialisées..

Il s'agit des propriétés suivantes :

  1. couleur_carte = "violet"
  2. compare_code_pin

Dans ce cas-ci, tu donnes une valeur par défaut à ces propriétés. Chaque objet d'instance aura cette propriété avec cette valeur par défaut lors de la construction de la classe.

Ce que je peux te dire sur le point 5) Des propriétés qui commencent par #

Il s'agit des propriétés suivantes :

  1. #code_pin
  2. #code_puk
  3. #genere_code_pin
  4. #genere_code_puk
  5. #genere_numero_carte

En orienté objet, les classes introduisent la notion d'encapsulation. Il s'agit de donner une visibilité aux propriétés. Il y a plusieurs visibilités et elles dépendent des langages.

En JavaScript, une propriété PEUT être soit publique, soit privée et lorsqu'elle est privée, elle est préfixée par le caractère #. Lorsqu'une propriété est privée, cela veut dire qu'elle n'est pas accessible par héritage, et par l'objet d'instance.

Par exemple sur l'objet d'instance:

let objet_instance = new CarteIdentité("S.", "Mike", "1991-12-07");
alert(objet_instance.prenom); // Affiche "Mike"
alert(objet_instance.#code_pin); // Interdit, ERREUR.
alert(objet_instance.code_pin); // Affiche undefined, cette propriété est inexistante.

Je reviendrai avec un exemple sur l'héritage plus tard, quand on y sera.

PhiSyX commented 1 day ago

Points clés d'une classe :

  1. Une classe PEUT avoir un constructeur.
class CompteBancaire {
    // Constructeur
    constructor(nom) {}
}
  1. Une classe est destinée à être instanciée en un objet.
let instance_objet = new CompteBancaire("Nom");

Le fait de d'appeler new sur une classe s'appelle le fait de créer une instance de classe. Une instance de classe partage les mêmes points clés qu'un objet.

  1. Une classe PEUT avoir des propriétés publiques ou privées.

Pour affecter une valeur à une propriété, on utilise this.

class CompteBancaire {
    nom; // <- Propriété publique
    #code_puk; // <- Propriété privée.
    #code_pin = "0000"; // <- Propriété privée avec une valeur par défaut.

    constructor(nom) {
        this.nom = nom;
        this.#code_puk = "0000";

        // Pas obligé de faire la ligne qui suit étant donnée
        // qu'il y a une valeur par défaut
        //this.#code_pin = "0000";
    }
}

Les propriétés privées ne peuvent être utilisées qu'au sein de la classe.

let instance_objet = new CompteBancaire("Nom");
console.log(instance_objet.nom); // Ok.
console.log(instance_objet.#code_pin); // Erreur.
  1. Une classe PEUT avoir des méthodes publiques ou privées.

Pour accéder à une propriété ou une méthode, on utilise this.

class CompteBancaire {
    nom;
    #code_pin;

    constructor(nom) {
        this.nom = nom;
        this.#code_pin = this.#générer_code_pin();
    }

    // Méthodes publiques.
    déposer(montant) {}
    retirer(montant) {}

    // Méthodes privées.
    #générer_code_pin() {
        return "0000";
    }
}

Les méthodes privées ne peuvent être utilisées qu'au sein de la classe.

let instance_objet = new CompteBancaire("Nom");
console.log(instance_objet.déposer(123)); // Ok.
console.log(instance_objet.retirer(123)); // Ok.
console.log(instance_objet.#générer_code_pin()); // Erreur.
  1. Une classe PEUT hériter des propriétés publiques et méthodes publiques d'une classe parente.

Pour accéder à une propriété ou une méthode, on utilise this.

Pour accéder à une propriété ou une méthode de l'objet parent, on utilise super si this n'est pas possible.

class CompteBancaire {
    #solde;

    constructor(solde) {
        this.#solde = solde;
    }

    déposer(montant) {}
    retirer(montant) {}

    getSolde() {
        return this.#solde;
    }
}

class CompteÉpargne extends CompteBancaire {
    constructor(solde, taux) {
        super(solde);

        this.taux = taux;
    }

    appliquer_intérêt() {
        let interet1 = this.getSolde() * this.taux; // Ok: Accès aux méthodes publiques de CompteBancaire
        //let interet2 = this.#solde * this.taux; // Erreur: Pas accès aux propriétés privées de CompteBancaire
        this.déposer(interet1);
    }
}
let instance_objet = new CompteÉpargne(500, 0.2);
console.log(instance_objet.appliquer_intérêt()); // Ok.
console.log(instance_objet.retirer(123)); // Ok.
console.log(instance_objet.#solde); // Erreur.