IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Précisions sur l'héritage [Débutant]


Sujet :

C#

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2020
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2020
    Messages : 2
    Par défaut Précisions sur l'héritage
    Bonjour,

    c'est mon premier post sur ce forum alors tout d'abord, bonjour à tous, je me présente un minimum.

    Je suis un complet novice qui suit les cours C#.

    J'ai découvert la programmation il y a très peu, de l'ordre de quelques semaines et je m'y intéresse beaucoup. Pour l'instant les cours sont portés sur la création de quelques applications console, comme celle qui suit.

    J'aime à rendre les exercices un peu plus durs mais aussi un peu plus personnels, au risque de me heurter, comme ici, à des choses qui me paraissent impossibles avec mes connaissances actuelles.

    Après plusieurs heures de tâtonnements sur VS et de recherches sur le net, j'en viens à vous demander de l'aide.

    Voici mon magnifique spaghetti (j'ai cru comprendre que ça ce disait comme ça ^^) le problème est résumé à l'intérieur puis en dessous.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
        public class Animal
        {
            protected string prenom;
     
            static void Main(string[] args)
            {
                List<Animal> leZoo = new List<Animal>();
     
                Chat Toulouse = new Chat("Toulouse"); leZoo.Add(Toulouse);
                Chat GrosRoux = new Chat("Gros Roux"); leZoo.Add(GrosRoux);
                Chat GrosNoir = new Chat("Gros Noir"); leZoo.Add(GrosNoir);
                Chat OG = new Chat("OG"); leZoo.Add(OG);
                Chat Eden = new Chat("Eden"); leZoo.Add(Eden);
                Chien Speed = new Chien("Speed"); leZoo.Add(Speed);
     
                foreach (Animal betes in leZoo) { betes.JouerAvecSesAmis(); }
     
                // Tout fonctionne et les animaux, tour à tour, appliquent la méthode JouerAvecSesAmis()
            }
     
            public void Respirer() { Console.WriteLine("Je suis " + prenom + " et je respire !"); }
     
            public void JouerAvecSesAmis()
            {
                Console.WriteLine("Je suis " + prenom + " et je m'amuse avec mes amis ! :) ");
     
                Respirer();
     
                // L'ajout de la méthode Respirer() fonctionne très bien, vu que définie dans la classe mère Animal.
     
                // Je souhaite maintenant que chacun Aboie ou Miaule selon sa classe, seulement je ne peux pas,
                // car les méthodes Aboyer() et Miauler() n'existent pas ici.
     
                // Voilà la représentation logique que je me fais de mon idée (évidemment ça ne fonctionne pas) :
     
                // if (class = Chien) { Aboyer(); }
                // if (class = Chat) { Miauler); }
     
                // Il faudrait dans un premier temps que j'arrive ici à invoquer les deux méthodes non présente dans la classe Animal, puis que j'identifie la méthode à appliquer selon la classe de chaque animal.
     
                // Quelqu'un aurait l'amabilité de m'aiguiller un minimum ? :)
            }
        }
     
        public class Chien : Animal
        {
            public Chien(string PrenomDuChien) { prenom = PrenomDuChien; }
     
            public void Aboyer() { Console.WriteLine("Wouuuuaf Wouaf !!!" + Environment.NewLine); }
        }
     
        public class Chat : Animal
        {
            public Chat(string PrenomDuChat) { prenom = PrenomDuChat; }
     
            public void Miauler() { Console.WriteLine("Miaouuuuuu !" + Environment.NewLine); }
        }
    On à donc, une classe mère "Animal" qui peut "Respirer(), et deux classes filles, Chien qui peut "Aboyer()" et Chat qui peut "Miauler().

    Je souhaite que la méthode "JouerAvecSesAmis()" définie dans la classe mère "Animal" fasse "Respirer()" tout le monde, "Aboyer()" les Chiens et "Miauler" les Chats.

    Je me doute que je ne suis pas assez clair ni que la construction de mon post est appropriée, donc n’hésitez pas à m'en faire part et avec vos conseils j'éditerai tout cela afin que ça soit plus compréhensible.

    Merci

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2009
    Messages
    155
    Détails du profil
    Informations personnelles :
    Localisation : France, Indre et Loire (Centre)

    Informations forums :
    Inscription : Février 2009
    Messages : 155

  3. #3
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    essaye de ne pas mettre 2 lignes de code par ligne
    essaye de trouver des exercices réalistes, faire aboyer un chat n'aide à comprendre la POO je pense
    après sur une appli console c'est ptete dur de trouver un truc réaliste, simple, "utile" et qui permet de faire de la POO, donc tu peux passer sur wpf (client lourd) ou asp.net (web) assez rapidement ou même xamarin (appli mobile)
    il y a 15 ans les noobs faisait une appli de gestion de dvdthèque, à l'heure de netflix ca a l'air d'être toujours le cas... mais il doit être possible de trouver mieux je pense ^^

    le void Main n'a rien à faire dans Animal
    il est censé être dans program.cs après c'est un fichier par classe (sauf cas rare ou classe privée)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  4. #4
    Membre Expert
    Avatar de PixelJuice
    Homme Profil pro
    Ingénieur .NET & Game Designer
    Inscrit en
    Janvier 2014
    Messages
    671
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur .NET & Game Designer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 671
    Par défaut
    Bonjour,

    Pour rajouter a ce qui a été déjà dit :

    En ce qui concerne Miauler() et Aboyer(), c'est une mauvaise idée de partir de la sorte, comme tu as pu t'en rendre compte. Il est possible de faire marcher le code que tu as commenté mais tu perdrais tout l’intérêt de l'héritage en faisant de la sorte.

    Il te faut rajouter dans ta classe Animal la méthode suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public abstract void Cri(); // Ou un autre nom si tu préfères
    Et ainsi la redéfinir dans Chien et Chat ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public override void Cri()
    {
         Console.WriteLine("Wouuuuaf Wouaf !!!" + Environment.NewLine); // Et "Miaou" pour les chats
    }
    Toute l'idée de l'héritage est d'être le plus généraliste possible, donc exit les noms & méthodes spécifiques pour chaque classe, c'est son comportement redéfini qui apportera la spécialisation.

    Le mot clé abstract te permet de définir une telle méthode.

    Et si tu ne veux pas que tu sois obligé de définir Cri pour chaque animal, tu peux utilisé le mot clé virtual comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public virtual void Cri() { } // Ou un autre nom si tu préfères
    Avec une méthode déclarée ainsi, tu as un corps par défaut et donc tu n'es pas obligé de la redéfinir pour chaque classe. Et faire comme ceci si jamais tu en as besoin :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public virtual void Cri() 
    { 
        Console.WriteLine("L'animal émit un son. " + Environment.NewLine)
    }
    Voilà tu peux t'amuser a faire des petits tests pour voir comment tout ça marche.

    Pour finir, c'est une bonne idée de faire ses propres exercices, c'est la méthode que j'utilisais quand je débutais, faire des mini-projets autour de sujets qui t'intéresse et de le créer tout en apprenant étape par étape (Jeux / Player MP3 / Chat / ...).

  5. #5
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Pour étendre ce qu'a dit PixelJuice dans ce contexte je te conseillerais de choisir l'option abstract. On peut créer un Chat, un Chien ou même une Sauterelle, mais pas un Animal qui est un concept abstrait ; en déclarant la classe Animal abstract ça empêchera de l'instancier. Et pour la méthode Cri() ce sera à voir si une méthode générique, sans effet, peut avoir du sens pour plusieurs types d'animaux, sinon le mieux est qu'elle soit abstract elle aussi afin d'obliger une classe fille à implémenter sa propre version.

  6. #6
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2020
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2020
    Messages : 2
    Par défaut
    Et bonjour,

    mes excuses pour cette réponse tardive, pas d'internet pendant quelques jours.

    Merci à tous, tout est rentré dans l'ordre, ils arrivent désormais à jouer et utiliser leurs cris respectifs, même le chat muet.

    En effet définir la méthode Cri() comme abstract a permis aux classes filles de se l'approprier facilement, j'ai rajouté une classe ChatAphone avec comme base la classe Chat et elle a aussi pu modifier la méthode Cri.

    Je ne voyait juste pas le problème sous le bon angle (ce qui, j'ai l'impression, est souvent le cas en programmation).

    J'y vois un peu plus clair grâce à vous, merci.

    @Pol63 : j'ai une idée très claire de jeu et je me suis lancé sur Unity (ne me demandez pas pourquoi, il faut bien commencer quelque part je suppose), je me suis rendu compte assez vite qu'il me fallait certaines notions, une fois que je les aurai acquises je me remettrai sur ce projet.

    @PixelJuice : super explication, au top. J'ai juste dû en plus changer la classe Animal en abstract, ce que conseillait Noxen juste après toi.

  7. #7
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par PixelJuice Voir le message
    Bonjour,

    Pour rajouter a ce qui a été déjà dit :

    En ce qui concerne Miauler() et Aboyer(), c'est une mauvaise idée de partir de la sorte, comme tu as pu t'en rendre compte. Il est possible de faire marcher le code que tu as commenté mais tu perdrais tout l’intérêt de l'héritage en faisant de la sorte.
    Je ne suis pas vraiment d'accord avec tout ça.

    L'héritage permet justement d'utiliser les spécificités des différentes classes à travers un contrat unique.

    C'est justement à la classe abstraite de se débrouiller pour savoir exposer ce qu'il faut, et aux classes dérivées de travailler convenablement à travers les méthodes communes.

    Je n'ai plus du tout en tête le nom du pattern, mais on peut parfaitement, depuis une méthode générique, appeler des méthodes spécifiques, tout simplement en rusant et en passant par des méthodes privées (protected).
    En effet, autant dans l'exemple scolaire, c'est toujours simple, mais dans la réalité, on ne va pas s'amuser à réécrire la moitié du code quand on décide d'implémenter à posteriori un héritage.

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
     
    using System;
    using System.Collections.Generic;
     
    namespace ExempleHeritage
    {
        class Program
        {
            static void Main(string[] args)
            {
                List<Animal> animaux = new List<Animal>();
                animaux.Add(new Chat("Félix"));
                animaux.Add(new Chien("Milou"));
                animaux.Add(new Chien("Bill"));
                animaux.Add(new Poisson("Némo"));
     
                foreach (Animal animal in animaux)
                {
                    animal.Jouer(animaux);
                }
            }
        }
     
        abstract class Animal
        {
            public string Nom { get; }
     
            public Animal(string nom)
            {
                Nom = nom;
            }
     
            protected virtual void Respirer()
            {
                Console.WriteLine("Je respire uf ! uf ! ");
            }
     
            public virtual void Jouer(List<Animal> autres)
            {
                Respirer();
                foreach (Animal animal in autres)
                {
                    if (animal != this)
                    {
                        switch (GetInteraction(animal))
                        {
                            case Comportement.Amical:
                                Console.WriteLine($"- {animal.Nom} est mon copain !");
                                break;
                            case Comportement.Peur:
                                Console.WriteLine($"- {animal.Nom} me fait peur !");
                                break;
                            case Comportement.Prédation:
                                Console.WriteLine($"- {animal.Nom} me donne faim !");
                                break;
                            case Comportement.Neutre:
                                Console.WriteLine($"- {animal.Nom} je m'en tampone !");
                                break;
                        }
                    }
                }
            }
     
            protected abstract Comportement GetInteraction(Animal autre);
     
            public enum Comportement
            {
                Neutre,
                Amical,
                Peur,
                Prédation
            }
        }
        class Chat : Animal
        {
            public Chat(string nom) : base(nom) { }
     
            public void Miauler()
            {
                Console.WriteLine($"{Nom} dit Miaou ! ");
            }
     
            public override void Jouer(List<Animal> autres)
            {
                Miauler();
                base.Jouer(autres);
            }
     
            protected override Comportement GetInteraction(Animal autre)
            {
                if (autre is Chat)
                {
                    return Comportement.Amical;
                }
                else if (autre is Chien)
                {
                    return Comportement.Peur;
                }
                else if (autre is Poisson)
                {
                    return Comportement.Prédation;
                }
                else
                {
                    return Comportement.Neutre;
                }
            }
        }
     
        class Chien : Animal
        {
            public Chien(string nom) : base(nom) { }
     
            public void Aboyer()
            {
                Console.WriteLine($"{Nom} dit : Wouf ! ");
            }
     
            public override void Jouer(List<Animal> autres)
            {
                Aboyer();
                base.Jouer(autres);
            }
     
            protected override Comportement GetInteraction(Animal autre)
            {
                if (autre is Chat)
                {
                    return Comportement.Amical;
                }
                else if (autre is Chien)
                {
                    return Comportement.Amical;
                }
                else
                {
                    return Comportement.Neutre;
                }
            }
        }
     
        class Poisson : Animal
        {
            public Poisson(string nom) : base(nom) { }
     
            protected override void Respirer()
            {
                Console.WriteLine($"{Nom} respire bloup ! bloup ! ");
            }
     
            public override void Jouer(List<Animal> autres)
            {
                base.Jouer(autres);
            }
     
            protected override Comportement GetInteraction(Animal autre)
            {
                if (autre is Poisson)
                {
                    return Comportement.Amical;
                }
                else
                {
                    return Comportement.Peur;
                }
            }
        }
    }

    Félix dit Miaou !
    Je respire uf ! uf !
    - Milou me fait peur !
    - Bill me fait peur !
    - Némo me donne faim !
    Milou dit : Wouf !
    Je respire uf ! uf !
    - Félix est mon copain !
    - Bill est mon copain !
    - Némo je m'en tampone !
    Bill dit : Wouf !
    Je respire uf ! uf !
    - Félix est mon copain !
    - Milou est mon copain !
    - Némo je m'en tampone !
    Némo respire bloup ! bloup !
    - Félix me fait peur !
    - Milou me fait peur !
    - Bill me fait peur !
    -- Edit : bon, en me relisant, je me rend compte que le pattern dont j'ai parlé, je n'en ai finalement pas eu besoin... La simple surcharge des méthodes communes permet d'appeler les méthodes spécifiques à chaque classe dériviée.

  8. #8
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    ce sont deux choses différentes
    ce que présente PixelJuice est la base simple, et au passage avec l'implémentation virtual ca permet de ne pas hériter
    après quand on veut traiter des comportements différents là oui il faut du code quelque part pour le faire
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  9. #9
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    ce sont deux choses différentes
    ce que présente PixelJuice est la base simple, et au passage avec l'implémentation virtual ca permet de ne pas hériter
    après quand on veut traiter des comportements différents là oui il faut du code quelque part pour le faire
    Oui, mais justement, l'exemple avec "Miauler()" et "Aboyer()" c'est justement d'illustrer qu'on a des traitements différents. On ne veut donc pas forcément les encapsuler dans un nom générique "Crier()" car les paramètres peuvent être différents, les types de retour, etc. sans oublier la sémantique.

    C'est pour ça qu'à mon avis il ne faut surtout pas s'empêcher de spécialiser les classes dérivées, au contraire... car sinon, autant de pas hériter et faire un gros switch() dans la super-classe.

  10. #10
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    c'est surtout pour ca que faire des cours sur la POO avec des animaux c'est débile

    mais bon structurellement parlant, faire du bruit c'est bien générique, qu'un chat miaule et qu'un chien aboie on s'en fout tant qu'ils ont fait leur bruit, donc une méthode PayeTonCri() suffit amplement
    mais bon c'est un point de vue, et sur des choses plus concrètes c'est plus simple à trancher, et dans le pire des cas ca reste un choix du développeur

    après si certains doivent faire des trucs que d'autres ne font pas c'est une interface, pas une enum
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  11. #11
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    après si certains doivent faire des trucs que d'autres ne font pas c'est une interface, pas une enum
    J'ai pas compris cette dernière phrase.

    A propos de mon enum ?
    Il ne s'agit pas dans mon exemple de faire ou pas faire (ça, c'est la surcharge de la méthode générique "Jouer()") qui le fait, mais surtout de montrer qu'on peut :
    - Prévoir des interactions entre classes dérivées directement dans la classe abstraite
    - Implémenter de façon spécifique ces comportements dans les classes dérivées

    Le enum servant uniquement ici à mettre enforme le résultat de ces interactions.

  12. #12
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Citation Envoyé par StringBuilder Voir le message

    Citation Envoyé par PixelJuice Voir le message
    Bonjour,

    Pour rajouter a ce qui a été déjà dit :

    En ce qui concerne Miauler() et Aboyer(), c'est une mauvaise idée de partir de la sorte, comme tu as pu t'en rendre compte. Il est possible de faire marcher le code que tu as commenté mais tu perdrais tout l’intérêt de l'héritage en faisant de la sorte.
    Je ne suis pas vraiment d'accord avec tout ça.

    L'héritage permet justement d'utiliser les spécificités des différentes classes à travers un contrat unique.

    C'est justement à la classe abstraite de se débrouiller pour savoir exposer ce qu'il faut, et aux classes dérivées de travailler convenablement à travers les méthodes communes.
    Pour moi c'était justement ce que PetitFlo avait mal compris sur l'héritage et que PixelJuice a correctement corrigé. Le fameux contrat unique est la méthode Cri() qui va être redéfinie dans les classes enfant pour faire miauler un chat et aboyer un chien. C'est la situation que l'on pourrait rencontrer avec une hiérarchie de composants graphiques qui doivent disposer d'une méthode public virtual void Paint(Graphics g){}.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    namespace ExempleHeritage
    {
        abstract class Animal
        {
            public virtual void Jouer(List<Animal> autres)
            {
                Respirer();
                foreach (Animal animal in autres)
                {
                    if (animal != this)
                    {
                        switch (GetInteraction(animal))
                        {
                            case Comportement.Amical:
                                Console.WriteLine($"- {animal.Nom} est mon copain !");
                                break;
                            case Comportement.Peur:
                                Console.WriteLine($"- {animal.Nom} me fait peur !");
                                break;
                            case Comportement.Prédation:
                                Console.WriteLine($"- {animal.Nom} me donne faim !");
                                break;
                            case Comportement.Neutre:
                                Console.WriteLine($"- {animal.Nom} je m'en tampone !");
                                break;
                        }
                    }
                }
            }
    Ta méthode Jouer() ressemble quand même beaucoup à une méthode définitive qui n'a pas besoin d'être redéfinie dans les classes enfant. Elle crée une structure de traitement qui est imposée et seuls les comportements spécifiques sont à redéfinir ; tu pourrais y ajouter un appel à une méthode virtuelle Cri() et les classes filles auront juste à définir l'implémentation qui leur correspond. Ça me fait penser au dispose pattern pour l'implémentation de IDisposable.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     
    namespace ExempleHeritage
    {
        class Chat : Animal
        {
            protected override Comportement GetInteraction(Animal autre)
            {
                if (autre is Chat)
                {
                    return Comportement.Amical;
                }
                else if (autre is Chien)
                {
                    return Comportement.Peur;
                }
                else if (autre is Poisson)
                {
                    return Comportement.Prédation;
                }
                else
                {
                    return Comportement.Neutre;
                }
            }
        }
     
        class Chien : Animal
        {
            protected override Comportement GetInteraction(Animal autre)
            {
                if (autre is Chat)
                {
                    return Comportement.Amical;
                }
                else if (autre is Chien)
                {
                    return Comportement.Amical;
                }
                else
                {
                    return Comportement.Neutre;
                }
            }
        }
     
        class Poisson : Animal
        {
            protected override Comportement GetInteraction(Animal autre)
            {
                if (autre is Poisson)
                {
                    return Comportement.Amical;
                }
                else
                {
                    return Comportement.Peur;
                }
            }
        }
    }
    Ce qui m'ennuie avec cette approche c'est que plus ou moins chaque classe connaît chaque autre classes et du coup ce système est difficile à étendre. Si on veut rajouter une classe (Loup, Mouton, Crocodile, Plancton...) il y a non seulement la nouvelle classe a implémenter mais il faut également modifier toutes les autres classes pour prendre en compte la nouvelle dans leur comportement (cf. l'open-closed principle).

  13. #13
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Noxen Voir le message
    Ce qui m'ennuie avec cette approche c'est que plus ou moins chaque classe connaît chaque autre classes et du coup ce système est difficile à étendre. Si on veut rajouter une classe (Loup, Mouton, Crocodile, Plancton...) il y a non seulement la nouvelle classe a implémenter mais il faut également modifier toutes les autres classes pour prendre en compte la nouvelle dans leur comportement (cf. l'open-closed principle).
    Y'a le else pour ça

    Mon exemple malheureusement impose de faire comme ça : un animal ne peut pas savoir comment réagir vis à vis d'un autre sans le connaître.
    Après, on pourrait déduire un comportement prévisible en fonction de certaines propriétés (poids, taille, présence croc, etc.) mais bon, on n'en est pas là

  14. #14
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    Y'a le else pour ça

    Mon exemple malheureusement impose de faire comme ça : un animal ne peut pas savoir comment réagir vis à vis d'un autre sans le connaître.
    Après, on pourrait déduire un comportement prévisible en fonction de certaines propriétés (poids, taille, présence croc, etc.) mais bon, on n'en est pas là
    Effectivement là on irait un peu loin du sujet de départ, tu as proposé une solution par rapport au contexte, auquel il n'était pas forcément simple de répondre. D'ailleurs mon dernier point se voulait plus une remarque générale sur une difficulté d'architecture déjà identifié dans la littérature. On s'efforce tous de contribuer pour faire avancer les choses (personnellement je lis tes remarques sur les bases de données avec attention).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Précision sur l'héritage / height
    Par friendofweb dans le forum Mise en page CSS
    Réponses: 8
    Dernier message: 11/11/2016, 11h57
  2. Précisions sur héritage
    Par reymsKoola dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 24/02/2015, 23h09
  3. Précision sur Oracle 9iAS r2
    Par Patmane dans le forum Oracle
    Réponses: 9
    Dernier message: 18/03/2007, 05h41
  4. [Observateur] Précisions sur le design pattern Observer [UML]
    Par joquetino dans le forum Design Patterns
    Réponses: 2
    Dernier message: 07/10/2004, 23h35
  5. Précision sur les sauvegarde à chaud
    Par alxkid dans le forum Administration
    Réponses: 2
    Dernier message: 09/08/2004, 19h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo