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 :

Propriétés get et set séparées dans deux interfaces.


Sujet :

C#

  1. #1
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    269
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 269
    Points : 460
    Points
    460
    Par défaut Propriétés get et set séparées dans deux interfaces.
    Bonjour tous le monde,

    Aujourd'hui je suis face à un cas de consience. Est-ce sale de casser l'heritage dans une interface dans le but de séparer le getter du setter ?

    Peut etre qu'un bou de code sera plus parlant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface IPerson
    {
      string Name { get; }
    }
     
    internal interface IPersonWriteable : IPerson
    {
      new strnig Name { get; set; }
    }
    C'est le fait d'être obliger de reprendre get, et d'utiliser new, qui m'a intrigué.

    Mon besoin réel est légèrement différent du cas ci-dessus. Mais la question reste entière, est-ce sale? Ou est-ce une faiblesse du language/compilateur qui m'oblige à mettre "new" et reprendre le getter ?

    Oui je sais, c'est une question délicate pour un vendredi après midi

  2. #2
    Membre chevronné Avatar de Er3van
    Homme Profil pro
    Architecte Logiciel
    Inscrit en
    Avril 2008
    Messages
    1 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte Logiciel
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2008
    Messages : 1 430
    Points : 2 227
    Points
    2 227
    Par défaut
    Selon moi, oui, tu casses l'héritage.

    Logiquement si ton IPerson ne doit pas être "settable", alors quelque chose qui hérite de cette interface ne devrait pas l'être non plus.

    Ne serait-ce pas plus logique d'avoir un set dans IPerson, et deux interfaces IPersonReadOnly (get uniquement) + IPersonWriteable (get + set) qui héritent de IPerson ?

    Ou alors j'ai raté un truc... vendredi après-midi quand tu nous tiens
    One minute was enough, Tyler said, a person had to work hard for it, but a minute of perfection was worth the effort. A moment was the most you could ever expect from perfection.

    -- Chuck Palahniuk, Fight Club, Chapter 3 --

  3. #3
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    269
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 269
    Points : 460
    Points
    460
    Par défaut
    Citation Envoyé par Er3van Voir le message
    Ne serait-ce pas plus logique d'avoir un set dans IPerson
    ...
    Ou alors j'ai raté un truc... vendredi après-midi quand tu nous tiens
    Le fait que si tu met un set sur IPerson, il sera forcement public sur la classe qui implemente IPerson.

    En gros, je ne veux pas exposer le setter à tous le monde. Pour clarifier un peu la situation, j'ai modifié l'exemple en rendant IPersonWriteable internal.

  4. #4
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour

    Le new dans l'heritage de class ou interface signifie ajout d'une nouvelle methode en plus de l'existante avec meme nom et signature...
    2 methodes vont exister dans l'interface et les appels au methodes doivent se faire via l'interface pour les distinguer...
    Si tu demandes une implementation explicite tu seras eclaire sur le fonctionnement interne....et donc comment l'adapter au besoin....

    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
     
     public interface IPerson
        {
            string Name { get; }
        }
     
        public interface IPersonWriteable :IPerson 
        {
          new   string Name { get; set; }
     
        }
     
        public class Person :IPersonWriteable 
        {
     
            private string n;
            string IPersonWriteable.Name
            {
                get
                {
                    return n; 
                }
                set
                {
                    n = value;
                }
            }
     
            string IPerson.Name
            {
                get { return n; }
            }
    bon code..............

  5. #5
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    269
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 269
    Points : 460
    Points
    460
    Par défaut
    Je connais bien la définition de "new", je sais tres bien aussi utiliser l'implementation explicite d'une interface.

    Ma question n'est peut être pas assez clair. Aller hop reformulation, et autre exemple.
    Je cherche a savoir si mon premier exemple est valide d'un point de vue POO ?
    Je cherche simplement a étendre un contrat. En C# un contrat est représenté par une interface. Comme j'utilise dans le cas présent des propriétés, je suis obligé de re-déclarer la propriété.
    Du fait que je re-declare la propriété, suis-je réelement obligé de mettre "new" ? (Voir la fin du post pour un mystère de plus)
    Le faire est-ce aller à l'encontre de la POO, ou est-ce C# qui empêche d'utiliser correctement une interface.

    Pour aider à la réflexion qui m'habite un autre exemple :
    Sans utiliser de propriété
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface IPerson
    {
      string GetName();
    }
     
    internal interface IPersonWriteable : IPerson
    {
      void SetName(string name);
    }
    En ce passant de propriété il n'y a aucun problème.

    Pire encore en faisant des test je me suis aperçus que le code suivant compile sans erreur, sans warning (même niveau 4), et fonctionne parfaitement.
    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
        public interface IPerson
        {
            string Name { get; }
        }
     
        public interface IPersonWritable : IPerson
        {
            string Name { get; set; }
        }
     
        public class Person : IPersonWritable
        {
            private string _name;
     
            public string Name
            {
                get { return _name; }
                set { _name = value; }
            }
        }
     
            public static void Test()
            {
                IPersonWritable p = new Person();
                p.Name = "TOTO";
     
                IPerson readOnlyPerson = p;
                Console.WriteLine("IPersonWritable.Name : {0}", p.Name);
                Console.WriteLine("IPerson.Name : {0}", readOnlyPerson.Name);
            }
    A la vue de cet exemple, soit "new" est mal géré, soit C# a une implémentation plus logique des interfaces au niveau des propriétés, même si cela semble incorrect à la première lecture.
    Ce qui me ramène à la nécessité réel ou non de l'utilisation de "new" dans ce cas?

  6. #6
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    rebonjour antoine.debyser

    Je me suis peut etre mal explique ..
    Cela veut dire foin de l'interface IPerson...
    Car un class implementant IPerson (ou l'on ne peut pas setter prop Name) verrait sa prop sette facilement via un autre class PersonWritable implementant IPersonWritable :
    comme le montre ce code:
    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
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    namespace WindowsFormsApplication1
    {
        public interface IPerson
        {
            string Name { get;  }
        }
     
        public interface IPersonWriteable :IPerson 
        {
          new   string Name { get; set; }
     
        }
        public class Person : IPerson
        {
     
     
            private string n = "IPerson";
     
            public string Name
            {
                get { return n; }
            }
        }
     
        public class PersonWritable:IPersonWriteable 
        {
     
     
            private string n = "IPersonWriteable ";
     
            public string Name
            {
                get
                {
                    return n;
                }
                set
                {
                    n=value;
                }
            }
        }
    }
    code .cs du test:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    private void button1_Click(object sender, EventArgs e)
            {
                IPerson person1 = new Person();
                textBox1.Text = person1.Name;
     
                IPersonWriteable person2 = new PersonWritable();
                person2.Name="malvenu";
                person1 = (IPerson)person2;
                textBox2.Text = person1.Name + " - " + person2.Name;
     
     
             }
    C'est pour cela que j'ai attire ton attention sur l'ajout car un type implementant IPersonWritable peut etre caste en IPerson a cause de l'heritage d'interface...
    Par contre l'inverse n'est pas possible et ne compile pas pour plus de surete.....
    Maintenant tout depend du besoin....
    bon code.....

  7. #7
    Membre actif
    Homme Profil pro
    Chef de Projet
    Inscrit en
    Décembre 2012
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Chef de Projet
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Décembre 2012
    Messages : 113
    Points : 260
    Points
    260
    Par défaut
    Bonjour,

    Citation Envoyé par MABROUKI Voir le message
    Car un class implementant IPerson (ou l'on ne peut pas setter prop Name) verrait sa prop sette facilement via un autre class PersonWritable implementant IPersonWritable :
    Si j'ai bien compris, tu indiques que le nom d'une IPerson peut être modifié via le setter en passant par l'interface IPersonWriteable.

    C'est uniquement vraie si l'instance contenue dans une variable de type IPerson est une instance d'une classe implémentant IPersonWriteable.

    Dans ton exemple, tu essaies de montrer que le nom de person1 est modifié. Ce n'est pas vrai. Ce n'est pas le nom qui est modifié, mais l'instance référencée par person1 à la ligne 9.

    Il n'est pas possible de modifier le nom de l'instance créée via new Person()

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Points : 1 050
    Points
    1 050
    Par défaut
    Salut
    ------

    Bon, je fais peut-être erreur, mais selon moi il n'y a aucun problème dans ce qui est expliqué et c'est une mauvaise interprétation des interfaces et des héritages qui explique ce qui semble être une anomalie.

    Une interface, c'est un contrat. Hériter une interface d'une autre interface, c'est hériter un contrat d'un contrat. Dans le cas en question, ça ne veut en aucun cas dire qu'une classe implémentant l'interface IPersonWritable est une classe qui hérite d'une autre implémentant IPerson. Il n'y a donc ici aucun défaut au niveau de l'héritage, on ne casse rien.

    Pour être plus explicite :

    Si classe1 implémente l'interface IPerson, ça veut dire qu'elle doit fournir au minimum un accesseur "get" pour la propriété "Name".

    Ça ne veut en aucun cas dire que "Name" ne dispose pas d'un accesseur "Set", ça veut juste dire que ce n'est pas imposé par le contrat.

    Dit autrement, mettre uniquement l'accesseur "Get" pour la propriété "Name" ne veut en aucun cas dire que "Name" est en lecture seule, le contrat n'impose pas l'absence de "Set" mais bien la présence de "Get".

    Partant de là, si on dérive l'interface, ça revient simplement à ajouter des clauses au contrat. Ainsi, dans ce cas, on ajoute l'obligation de l'accesseur "Set".

    Est-ce que ça casse l'héritage? Ben non, il n'y a aucune notion d'héritage au niveau des classes, et au niveau des contrats le contrat IPersonWritable respecte bien l'héritage, puisque le contrat IPerson dit "on impose l'accesseur Get" et IPersonWritable dit "Et en plus on impose l'accesseur Set".

    Bref, si on a l'illusion que la classe implémentant IPerson a une propriété "Name" en lecture seule, ce n'est vrai QUE si on fournit une référence de la classe en tant que contrat IPerson, et donc ça ne donne simplement pas à l'utilisateur la possibilité d'utiliser "set" puisque sa présence n'est pas garantie. La classe, elle, peut fort bien disposer d'un "Set" sur "Name", c'est juste qu'au niveau du contrat on ne le voit pas.

    Or, une classe qui propose l'accesseur "Set" + "Get" (donc IPersonWritable) propose bien de fait l'accesseur "Get" (donc IPerson), et donc tout est respecté et il n'y a aucun bris de l'héritage nulle part.

    Logiquement si ton IPerson ne doit pas être "settable"
    Toute la confusion (selon moi) est résumée par cette phrase: Le contrat IPerson ne dit en aucun cas que "Name" ne doit pas être "settable", il dit juste qu'il doit être "Gettable" (si j'ose dire).

    C'est comme avec tout contrat de la vie réelle. Si L'Europe impose un contrat de vente avec au moins 2 ans de garantie et qu'un constructeur décide d'hériter de ce contrat en augmentant la garantie à 5 ans, il respecte bien le contrat dont il hérite, il n'y a aucun défaut d'héritage.

    En gros, je ne veux pas exposer le setter à tous le monde
    Tu fournis une référence à ta classe castée en IPerson, et pour ceux qui ont accès au "set", tu fournis ta classe castée en IPersonWritable. C'est exactement le rôle des contrats, donc tu ne commets à mon avis aucune "infraction" aux notions d'héritage et d'objet. Le constructeur dans mon exemple ci-dessus peut fort bien fournir le contrat de garantie de 2 ans pour un pays et celui de 5 ans pour un autre pays, concernant le même produit, et sans remettre en cause la législation.

    A+
    Claude

  9. #9
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Points : 2 925
    Points
    2 925
    Par défaut
    Plusieurs remarques.

    Déjà, comme le dit Claude, il n'y a rien de choquant à ce qu'une classe ait une propriété get set alors que l'interface ne mentionne que le get.

    Ensuite, as-tu besoin de IPersonWritable ? Auras-tu plusieurs classes qui vont l'implémenter ? Veux tu masquer l'implémentation de Person à des modules qui pourraient éventuellement manipuler des IPersonWritable ?

    Person est-il un bête DTO ? Dans ce cas, je serais plus que dubitatif sur l'emploi d'interfaces. Si au final ta classe Person n'implémente IPerson que via un bête get/set, tu ne gagnes rien à la planquer derrière une interface. Les classes non-DTO, c'est évidemment une autre histoire.
    ಠ_ಠ

  10. #10
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    269
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 269
    Points : 460
    Points
    460
    Par défaut
    Bonjour,

    merci pour vos réponses, j'ai moi même fait quelques avancées sur le sujet.

    Déjà, je vois que je suis arrivé à la même conclusion que ClaudeBg, mais sa formulation est tellement plus clair que la mienne.

    Ensuite, petit raté dans mes tests, le cas évoquer dans mon 3ieme post, compile avec un Warning (le fait qu'il n'y ai pas de new).

    Enfin pour Guulh, mon cas réel n'est pas aussi trivial, Il s'agit de mettre en commun deux interfaces qui n'ont rien avoir fonctionnellement entre elles, mais qui présentent des objets ayant les mêmes caractéristiques. Pourquoi mettre en commun, pour mutualiser la logique d'affichage.
    Sinon dans un cas plus proche de l'exemple, il est clair que cette séparation n'a d’intérêt que dans une logique métier. Certain peuvent écrire, d'autre non.

    Du coup, je pense que je vais marquer le sujet comme résolu.
    Avec la conclusion suivante, "non c'est n'est pas sale"

  11. #11
    Membre habitué
    Homme Profil pro
    Inscrit en
    Avril 2013
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2013
    Messages : 76
    Points : 143
    Points
    143
    Par défaut
    Citation Envoyé par antoine.debyser Voir le message
    Enfin pour Guulh, mon cas réel n'est pas aussi trivial, Il s'agit de mettre en commun deux interfaces qui n'ont rien avoir fonctionnellement entre elles, mais qui présentent des objets ayant les mêmes caractéristiques. Pourquoi mettre en commun, pour mutualiser la logique d'affichage.
    Pourquoi ne pas faire une troisième interface pour les caractéristiques communes dont tu aura besoin pour l'affichage?

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

Discussions similaires

  1. Mêmes méthodes dans deux interfaces héritées
    Par ShaiLeTroll dans le forum C++Builder
    Réponses: 0
    Dernier message: 25/07/2011, 18h24
  2. Réponses: 2
    Dernier message: 07/01/2010, 11h41
  3. Relier les champs de deux tables dans une interface graphique
    Par laurentlorient dans le forum Débuter
    Réponses: 1
    Dernier message: 26/04/2009, 22h34
  4. [Séquence] Méthodes get et set dans un diagramme de séquences
    Par La Pomme dans le forum Autres Diagrammes
    Réponses: 6
    Dernier message: 05/10/2008, 21h17
  5. Get et Set du texte dans un wxStaticText
    Par Amybond dans le forum wxWidgets
    Réponses: 2
    Dernier message: 15/10/2007, 22h30

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