Polar Code 🎭

Command Palette

Search for a command to run...

03
Pièce N°03

Chapitre 2 — L'Héritage Empoisonné

Dans la jungle du tas, il n'y a pas que des variables solitaires.
Il y a des familles. Des hiérarchies. Des lignées qui se disputent la mémoire.
Bienvenue dans la Programmation Orientée Objet.
Où chaque classe a ses secrets, et chaque héritage cache un couteau.

5. Classes et objets

Définition d'une classe
Un moule à objets. Un contrat. Un plan pour fabriquer des entités qui vivront, respireront, et mourront dans le tas.

public class Tueur
{
    // L'intérieur. Le caché.
    // Ce qui fait de lui ce qu'il est.
}

Champs, propriétés, méthodes
La trinité du pouvoir.

public class Espion
{
    // Champ - la donnée brute, souvent privée
    private string _nomDeCode;  // Tu ne dois pas savoir
    
    // Propriété - l'interface contrôlée
    public string Identite { get; set; }  // Ce que je veux bien te montrer
    
    // Méthode - l'action
    public void RemplirRapport(string details)
    {
        // Le travail se fait ici
        Console.WriteLine($"Rapport : {details}");
        _nomDeCode = "Ombre";  // On peut toucher aux champs privés
    }
}

Encapsulation
L'art de cacher ce qui doit l'être. Le premier principe. Le plus violé.

public class CoffreFort
{
    private int _codeSecret = 4729;  // Privé. Inaccessible.
    private int _tentatives = 0;
    
    // Propriété avec validation
    public decimal Montant 
    { 
        get => _montant;
        set
        {
            if (value >= 0)  // Garde-fou
                _montant = value;
            else
                Console.WriteLine("Vol détecté.");
        }
    }
    private decimal _montant;
    
    // Méthode publique pour interagir avec le privé
    public bool TenterCode(int code)
    {
        _tentatives++;
        return code == _codeSecret;  // Retourne un bool, garde le secret
    }
}

Constructeurs
L'accouchement d'un objet. Le moment où la mémoire s'alloue et où tout commence.

public class Contrat
{
    public string Cible { get; }
    public decimal Prix { get; }
    public DateTime Echeance { get; }
    
    // Constructeur - donne vie avec des valeurs initiales
    public Contrat(string cible, decimal prix, DateTime echeance)
    {
        // Validation au berceau
        if (string.IsNullOrEmpty(cible))
            throw new ArgumentException("Une cible doit avoir un nom.");
            
        Cible = cible;
        Prix = prix;
        Echeance = echeance;
        
        Console.WriteLine($"Nouveau contrat : {cible} - {prix:C}");
    }
    
    // Surcharge - un autre chemin vers la vie
    public Contrat(string cible) : this(cible, 50000, DateTime.Now.AddDays(7))
    {
        // Prix et échéance par défaut
        // 'this' appelle le constructeur principal
    }
}

// Utilisation
var contrat1 = new Contrat("Le Baron", 100000, DateTime.Now.AddDays(3));
var contrat2 = new Contrat("Le Rat");  // Utilise les valeurs par défaut

6. Propriétés avancées

Propriétés automatiques
La paresse élégante. Le compilateur fait le sale boulot.

public class Arme
{
    // Propre, concis
    public string Modele { get; set; } = "Glock 17";  // Avec valeur par défaut
    public int Munitions { get; set; } = 12;
    
    // Propriété calculée - une illusion maintenue
    public bool EstVide => Munitions <= 0;  // Expression-bodied
}

Accesseurs get / set personnalisés
Quand la propriété simple ne suffit plus.

public class Portefeuille
{
    private decimal _argent = 0;
    
    public decimal Argent
    {
        get 
        { 
            Console.WriteLine($"Quelqu'un regarde l'argent : {_argent:C}");
            return _argent; 
        }
        set 
        {
            if (value < 0)
            {
                Console.WriteLine("Tentative de dette détectée.");
                return;
            }
            
            decimal difference = value - _argent;
            if (difference > 10000)
                Console.WriteLine("Alerte : gros dépôt suspect!");
                
            _argent = value;
        }
    }
}

Propriétés en lecture seule
Une promesse gravée dans le marbre.

public class Dossier
{
    // Initialisation soit dans le constructeur...
    public string Numero { get; }  // Pas de set !
    
    // ...soit directement
    public DateTime DateCreation { get; } = DateTime.Now;
    
    public Dossier(string numero)
    {
        Numero = numero;  // Une seule chance de définir
        // Après ça, Numero est immuable
    }
    
    // Expression-bodied property
    public bool EstExpire => DateCreation.AddYears(10) < DateTime.Now;
}

Initialisateurs d'objets
La construction rapide. Trop rapide parfois.

// Au lieu de...
var espion1 = new Espion();
espion1.Nom = "Bond";
espion1.Matricule = "007";
espion1.EstActif = true;

// ...on peut faire
var espion2 = new Espion 
{
    Nom = "Bourne",
    Matricule = "Delta",
    EstActif = true
    // Attention : le constructeur s'exécute D'ABORD
    // Puis les propriétés sont settées
};

// Avec une classe anonyme (danger : pas de type défini)
var cible = new 
{
    Nom = "Drax",
    Localisation = "Venise",
    Dangerosite = 9
};

7. Héritage et polymorphisme

Héritage simple
L'ADN du code. Un parent, un enfant. Des gènes partagés, des secrets révélés.

public class Personne  // Classe mère
{
    public string Nom { get; set; }
    public DateTime DateNaissance { get; set; }
    
    public virtual void SePresenter()
    {
        Console.WriteLine($"Je m'appelle {Nom}.");
    }
}

public class Tueur : Personne  // Tueur hérite de Personne
{
    public string Specialite { get; set; }
    
    // Redéfinition
    public override void SePresenter()
    {
        base.SePresenter();  // Appelle la version parent
        Console.WriteLine($"Spécialité : {Specialite}.");
    }
    
    // Nouvelle méthode spécifique
    public void ExecuterContrat(string cible)
    {
        Console.WriteLine($"Contrat sur {cible} exécuté.");
    }
}

Méthodes virtuelles
Des portes laissées entrouvertes pour que les enfants les poussent.

public class Agent
{
    public virtual string ObtenirIdentite()
    {
        return "Identité classifiée";
    }
    
    // Méthode scellée - pas de redéfinition possible
    public sealed void TerminerMission()
    {
        Console.WriteLine("Mission terminée.");
    }
}

public class AgentDouble : Agent
{
    // On peut redéfinir le virtuel
    public override string ObtenirIdentite()
    {
        return "L'identité change selon le jour";
    }
    
    // Mais pas le scellé
    // public override void TerminerMission() { }  // ERREUR
}

Classes abstraites
Des fantômes. Des modèles qui ne vivront jamais seuls.

public abstract class Operation  // 'abstract' = on ne peut pas l'instancier
{
    // Propriété abstraite - doit être implémentée
    public abstract string Code { get; }
    
    // Méthode abstraite - doit être implémentée
    public abstract void Executer();
    
    // Méthode concrète - déjà implémentée
    public void Preparer()
    {
        Console.WriteLine($"Préparation de l'opération {Code}");
    }
}

public class Infiltration : Operation  // Doit implémenter les abstractions
{
    public override string Code => "NuitNoire";
    
    public override void Executer()
    {
        Console.WriteLine("Infiltration en cours...");
        // Code spécifique
    }
}

// var op = new Operation();  // ERREUR : abstraite!
var infiltration = new Infiltration();  // OK

8. Interfaces

Définition et implémentation
Des contrats sans chair. Des promesses que d'autres tiendront.

public interface IAssassin  // Convention : 'I' au début
{
    // Pas de champs, pas d'implémentation
    // Juste des signatures
    
    string NomDeCode { get; }
    void ExecuterCible(string cible);
    decimal DemanderPrix();
}

public interface IInfiltrable
{
    bool PeutInfiltrer(string lieu);
}

// Une classe peut implémenter plusieurs interfaces
public class Mercenaire : IAssassin, IInfiltrable
{
    public string NomDeCode { get; set; }
    
    public void ExecuterCible(string cible)
    {
        Console.WriteLine($"{NomDeCode} élimine {cible}");
    }
    
    public decimal DemanderPrix()
    {
        return 50000m;
    }
    
    public bool PeutInfiltrer(string lieu)
    {
        return lieu != "Fort Knox";  // Même les mercenaires ont des limites
    }
}

Différences classe abstraite / interface
Le choix entre un parent exigeant et plusieurs patrons.

// CLASSE ABSTRACITE :
// - Peut avoir des implémentations
// - Héritage simple uniquement
// - Peut avoir des champs
// - Modélise "EST UN"

// INTERFACE :
// - Pas d'implémentation
// - Implémentation multiple
// - Pas de champs (avant C# 8)
// - Modélise "PEUT FAIRE"

Injection par interface
La puissance du découplage. Travailler avec des fantômes.

public class ContratManager
{
    private readonly IAssassin _assassin;
    
    // On injecte une interface, pas une classe concrète
    public ContratManager(IAssassin assassin)
    {
        _assassin = assassin;  // Peut être n'importe quel IAssassin
    }
    
    public void FaireExecuterContrat(string cible)
    {
        decimal prix = _assassin.DemanderPrix();
        Console.WriteLine($"Prix : {prix:C}");
        
        _assassin.ExecuterCible(cible);
        // On ne sait pas qui exécute, ni comment
        // On sait juste qu'il respecte le contrat
    }
}

// Usage
IAssassin tueur = new Mercenaire { NomDeCode = "L'Ombre" };
var manager = new ContratManager(tueur);
manager.FaireExecuterContrat("Le Traître");

// Demain, on pourra injecter un autre type d'assassin
// Sans changer ContratManager

La fin de l'héritage.
Tu sais maintenant créer des familles d'objets.
Des hiérarchies qui s'étendent dans l'ombre.
Des contrats que certains remplissent, d'autres non.

Mais rappelle-toi :
L'héritage est un couteau à double tranchant.
Trop profond, et tu te noies dans la complexité.
Trop large, et tout devient public.

Une interface, c'est une promesse.
Une classe abstraite, c'est un destin partagé.
Un constructeur, c'est une naissance avec conditions.

Le prochain chapitre parlera des exceptions.
Des choses qui se brisent.
Des erreurs qu'on attrape, ou qu'on laisse tomber.

Dans le monde des objets, tout peut échouer.
Apprends à gérer l'échec.
Ou prépare-toi à planter proprement.