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 :

Héritage : incompatibilité static & abstract pour les méthodes


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2017
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 16
    Par défaut Héritage : incompatibilité static & abstract pour les méthodes
    Bonjour, je poursuis ma découverte de la Poo, du c#, du framework dotnet et de visual studio... Je ne doute de rien lol...

    J'ai bien compris l'incompatibilité conceptuelle entre static et abstract.

    Je suis pourtant devant un cas ou cela m'aurait été utile.

    Classiquement, je développe une programme de gestion d'une faune. Toute sorte d'animaux vivent, s'alimentent, se reproduisent, s’entre-tuent et meurent dans une environnement évolutif.
    Pas de problème pour gérer tout cela.
    La super classe Animaux contient une liste static que peuplent tous les constructeurs des classes finales.

    Or, il se trouve que peuvent survenir des changements brutaux qui n'affectent plus les individus-instances des diverses sortes d'animaux, mais les populations mêmes de ces classes.

    Bref, ceci:
    Nom : Animaux1.PNG
Affichages : 1130
Taille : 22,5 Ko

    Il me faudrait donc une méthode static, appelable donc depuis la classe même de chaque classe d'animaux, mais qui soit obligatoire, donc overridée, pour garantir la cohérence du programme.
    A chaque classe de définir sa propre variation de population selon les circonstances.

    Comment pourrais-je m'y prendre ?

    D'avance, merci.

  2. #2
    Expert confirmé

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 761
    Billets dans le blog
    21
    Par défaut
    Bonjour,

    Comme tu l'as bien compris, une méthode abstract static n'existe pas et n'a pas de sens, car la notion de polymorphisme nécessite d'avoir une instance et que les méthodes statiques travaillent n'ont pas sur une instance, mais sur la classe elle-même.

    Quelles sont donc les possibilités offertes ? Aucune qui réponde directement à tes attentes. Je vois cependant plusieurs approches possibles, chacune avec leurs avantages/inconvénients.

    La première, c'est de ne pas utiliser une méthode statique mais une méthode classique. Tu pourras utiliser l'héritage pour forcer l'implémentation de la méthode. Inconvénient, (qui n'en n'est pas forcément un) tu dois forcément appeler la méthode en utilisant une instance.

    La seconde, c'est de mettre en place un mécanisme de vérification en utilisant la réflexion. Pour chaque classe non abstraite dérivant de Animaux, tu regardes s'il existe la méthode statique que tu recherches. Si non, tu génères une erreur. Problème : cette vérification n'est faite qu'à l'exécution du code, pas à la compilation.

    Puisqu'on parle de compilation, il serait bon de savoir comment sont appelées ces méthodes justement. Si elles sont appelées directement (genre Lapin.KillThemAll()) alors le compilateur pourra être ton ami. Il ne te dira pas que la classe Lapin n'implémente pas la méthode statique abstraite, mais il te dira que la méthode est manquante. Par contre, tu ne pourras pas garantir que cette méthode portera le même nom dans toutes les classes... Si les méthodes sont appelées en utilisant la réflexion, alors on se retrouve dans le même cas que précédemment, tu ne pourras avoir une erreur qu'à l'exécution, et non à la compilation.

  3. #3
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2017
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 16
    Par défaut
    Merci pour ta réponse.

    Je me suis demandé si je ne pouvais pas passer par un interface qu'implémenteront toutes mes classes finales d'animaux.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    interface IPopulationVariable
        {
            void VarierPopulation(Environment env);
    }
    C'est depuis ma classe environnement qu'elle sera appelée en instanciant un animal.

    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
     public class Environnement
        {  //blabla...
     
    	    public string SubirGlaciation()
            {  //blabla...
                AffecterPopulations();
    		}
     
     
    		private void AffecterPopulations()
    		{
    		IPopulationVariable c = new Chien(true);
    		c.VarierPopulation (this);
    		IPopulationVariable l = new Lapin(true);
    		l.VarierPopulation(this);
    		IPopulationVariable o = new Otarie(true);
    		o.VarierPopulation(this);
    		//etc...

    Ce qui m'ennuie c'est que tous mes constructeurs remplissent ma faune:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public abstract class Animaux : IComparable
     
            public static List<Animaux> lstAnimaux = new List<Animaux>();  // regroupera tous les animaux créés pendant la session.
            // chaque constructeur y ajoutera l'objet instancié. Cela constituera l'ensemble de la faune présente (vivante) et passée (morte).
    Or les animaux instanciés pour AffecterPopulations() ne doivent évidemment pas s'y trouver !

    Je dois donc créer un constructeur qui n'ajoute pas à la list, un constructeur fantôme.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     class Chien : MammifereTerrestre, Inageant, IPopulationVariable // un chien peut nager pas tous les mammif terrestres.
        {
    		public void Chien(bool fantome) // Constructeur qui ne fait rien du tout. surtout il ne l'ajoute pas à lstAnimaux !
    		{}
     
    		//J'implémente la méthode de l'interface
    		public void VarierPopulation(Environnement env){}
    	}

    En terme de cohérence, ça marche très bien: en codant dans Environnement, je vois de suite que les classes animaux ont ce constructeur fantôme et qu'elles ont bien implémenté l'interface.

    Mais me reste une faille béante, je trouve: ce constructeur fantôme qui pourrait bien être appelé à mauvais escient pour instancier des animaux qui doivent se retrouver dans la faune ! Et là c'est imparable...

    Mon raisonnement se tient-il ?

    D'avance, merci.

  4. #4
    Expert confirmé

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 761
    Billets dans le blog
    21
    Par défaut
    Dans ce cas, il y a encore plusieurs approches.

    La "moins bien" (selon moi) serait de mettre tout cela dans un assembly à part, et de jouer avec la visibilité du constructeur (internal sera très bien). Ainsi, tu pourras utiliser le constructeur dans ton assembly et uniquement dans ton assembly en empêchant ainsi toute utilisation en dehors.

    L'autre solution, serait de remanier un peu le code, et d'introduire des collections d'animaux. Une collection génériques ListeAnimaux<T> où T est une classe dérivant de Animaux. Cette collection aurait une méthode pour instancier un animal et l'ajouter à la liste. Ensuite, il faut modifier ta classe Environnement pour ajouter autant de ListeAnimaux que tu as d'animaux

    PS : l'utilisation d'interface est généralement une bonne chose !

  5. #5
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2017
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 16
    Par défaut
    Merci François pour tes réponses. Je débute, certains concepts que tu évoques ne sont pas encore à ma portée.

    Dans le fond, ce qui me gène, c'est ce constructeur fantôme qui ne peuple pas ma faune et qui pourrait se trouver appelé à mauvais escient.
    Si je parvenais à le rendre private, le risque deviendrait quasi nul.

    Dans mes classes d'animaux, je crée donc un méthode statique CreerAnimalFantome() qui appelle ce constructeur devenu private

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
      public static Animaux CreerAnimalFantome()
            {Chien c = new Chien(true); //appel du constructeur fantome private
                return c;
            }
            private Chien(bool fantome) // constructeur rendu private
            { }
     
            public  void VarierPopulation(Environnement env)
            {
                Console.WriteLine("Population chiens impactée");
            }
    Ps je mets en return la super class Animaux car cette méthode à vocation à rejoindre une classe statique de méthodes partagées par toutes mes classes d'animaux.


    Donc, côté classe Environnement mon code pour affecter les populations devient:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     public string SubirVagueFroid()
            {//blabla
                AffecterPopulations();}
     
     private void AffecterPopulations()
            { IPopulationVariable c = (Chien)Chien.CreerAnimalFantome();
               c.VarierPopulation(this);
     
                IPopulationVariable l = (Lapin)Lapin.CreerAnimalFantome();
                l.VarierPopulation(this);
            }
    Et ça tourne impec !

    Nom : Animaux2.PNG
Affichages : 830
Taille : 13,0 Ko

  6. #6
    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
    Est-ce-que c'est le constructeur de la classe de base Animaux qui fait l'enregistrement dans la liste static ou c'est le constructeur de chaque classe enfant qui s'enregistre explicitement ?

Discussions similaires

  1. Réponses: 2
    Dernier message: 11/02/2014, 16h46
  2. [POO] Organisation classe pour les méthodes PDO
    Par altair8080 dans le forum Langage
    Réponses: 1
    Dernier message: 24/12/2013, 11h33
  3. Module PowerShell pour les méthodes d'extension
    Par Laurent Dardenne dans le forum Dvp.NET
    Réponses: 2
    Dernier message: 02/08/2010, 11h34
  4. Question pour les méthodes de string
    Par 0ColdZero0 dans le forum C++
    Réponses: 3
    Dernier message: 23/04/2009, 21h33
  5. Réponses: 3
    Dernier message: 13/06/2006, 14h52

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