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 :

Couplage parent enfant


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut Couplage parent enfant
    Bonjour,

    J'ai une classe Parent et une classe Child.
    Parent contient une propriété Childs qui est une collection de Child.
    Child contient une référence à Parent.

    J'aimerais que l'utilisateur ne puisse ajouter des Child à Childs que en passant par la classe Parent. J'ai donc écris ceci :

    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
     
        public class Parent
        {
            private List<Child> _ChildList = new List<Child>();
     
            public IEnumerable<Child> ChildList
            {
                get { return _ChildList; }
            }
     
            public void AddChild(Child c)
            {
                c.Parent = this;
                _ChildList.Add(c);
            }
        }
     
        public class Child
        {
            public Parent Parent { get; internal set; }
        }
    Le problème est que n'importe quel classe de l'assembly peut modifier la propriété Parent de la classe Child alors que seulement la classe Parent devrait pouvoir le faire.

    De plus, on peut modifier la propriété Childs sans passer par AddChild() en castant celle en List<Child>.

    Y a t-il des solutions à ces problèmes ? Un design pattern ou autre ?

    Merci d'avance.

  2. #2
    Rédacteur
    Avatar de The_badger_man
    Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2005
    Messages
    2 745
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 745
    Par défaut
    Pour éviter de modifier la propriété Childs, ne la renvoie pas par une propriété. Fait un énumérateur dessus avec GetEnumerator().

    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
     
    public class Parent : System.Collection.IEnumerable{
     
    private List<Child> _ChildList = new List<Child>();
     
    public System.Collection.IEnumerator GetEnumerator()  {
       foreach(child in _ChildList)
           yield return child;
    }
     
    public void AddChild(Child c){
                c.Parent = this;
                _ChildList.Add(c);
    }
    }
    Après tu peux faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Parent p = new Parent();
    foreach(Child c in p) {
      //bla bla
    }
    Les règles du forum
    Le trio magique : FAQ + Cours + fonction rechercher
    Mes articles
    Pas de questions par messages privés svp

    Software is never finished, only abandoned.

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    652
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 652
    Par défaut
    Citation Envoyé par maa Voir le message
    Le problème est que n'importe quel classe de l'assembly peut modifier la propriété Parent de la classe Child alors que seulement la classe Parent devrait pouvoir le faire.
    Ben vire le 'set' de la propriété Parent. Et passe le Parent dans le constructeur. Et passe tous les autres paramètres nécessaires à ce constructeur dans l'appel à AddChild, plutôt que de passer un objet Child directement. Et laisse le Parent s'occuper de créer son gamin.

    Citation Envoyé par maa Voir le message
    De plus, on peut modifier la propriété Childs sans passer par AddChild() en castant celle en List<Child>.
    Pour ça, tu peux utiliser _ChildList.AsReadOnly()
    Du côté du type renvoyé, tu peux laisser IEnumerable<T> ou passer à IList<T> pour avoir un peu plus de fonctions, au choix.
    Et si tu mets IEnumerable<T> et que certains veulent tricher en castant... ben ça leur plantera à la figure. Tant mieux. Ça leur apprendra à coder comme des veaux.

  4. #4
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    Si je ne peux modifier la propriété Parent que à la construction de l'objet, cela m'empêche de pouvoir bouger un Child vers un autre parent. Je suis obligé de le détruire et d'en créer un nouveau.

    Et si tu mets IEnumerable<T> et que certains veulent tricher en castant... ben ça leur plantera à la figure. Tant mieux. Ça leur apprendra à coder comme des veaux.
    Oui, mais je préférerais que ça bloque à la compilation... J'aimerais avoir une sorte List qui ne soit pas modifiable par l'utilisateur.

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Août 2003
    Messages
    835
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2003
    Messages : 835
    Par défaut
    Salut,

    Tu peux déclarer la méthode Set de ta propriété Parent "internal" au lieu de "public". ça n'a pas exactement le résultat demandé mais au moins les utilisateurs de ta bibliothèque ne pourront plus y accéder.

    Pour ce qui est de la liste de childs, la proposition de maniak d'utiliser la méthode AsReadOnly d'une liste me semble pas mal, sinon il te reste toujours la possibilité de faire une copie complete de ta liste et de la renvoyer.

  6. #6
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    Tu peux déclarer la méthode Set de ta propriété Parent "internal" au lieu de "public".
    Oui c'est ce que j'ai fais. Mais ce n'est pas l'idéal car le classe de l'assembly peuvent quand même setter la propriété Parent.

    Pour ce qui est de la collection, c'est vrai que je peux utiliser un enumerator, mais ça m'oblige à recopier tout les élément d'un collection privé à chaque accès... L'idéal serait peut être d'avoir une collection implémentant IList dont les méthode Add, Insert, Remove, RemoveAt... soient virtuelles, ainsi on pourrait en la dérivant contrôler la modification de celle-ci. Une telle classe existe-elle ?

  7. #7
    Membre émérite
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    652
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 652
    Par défaut
    Citation Envoyé par maa Voir le message
    Si je ne peux modifier la propriété Parent que à la construction de l'objet, cela m'empêche de pouvoir bouger un Child vers un autre parent. Je suis obligé de le détruire et d'en créer un nouveau.
    C'est un peu conceptuellement étrange si tu parles de parents/enfants, moins si tu parles de nodes/sous-nodes :)
    Auquel cas tu peux toujours faire une méthode MoveTo en passant un nouveau parent. Bon ok, au final ça revient au même, et oui du coup n'importe qui peut déplacer un enfant vers un autre parent. Mais c'est normal, dans ce cas-là, c'est fait pour.

    Éventuellement tu peux toujours passer d'autres paramètres dans cette méthode de déplacement pour vérifier 2-3 trucs supplémentaires, mais bon. Dans l'absolu ton problème est plus un léger flou artistique sur le design qu'un problème de langage.

    Citation Envoyé par maa Voir le message
    Oui, mais je préférerais que ça bloque à la compilation... J'aimerais avoir une sorte List qui ne soit pas modifiable par l'utilisateur.
    Là tu es limité à IEnumerable. Ou tu renvoies explicitement un ReadOnlyCollection<T> (dans la signature de ta propriété). Via cette classe, il n'y a pas de méthode d'ajout/suppression, etc.
    Par contre évidemment rien n'empêche de caster ça en IList<T> (et là c'est normal, pas du bidouillage à deux balles comme de caster de IList en List). C'est pas génialement fait du côté de .NET là. Il faudrait une interface avant IList qui n'ait que des membres en lecture seule. Y a pas, faut faire avec.

    Et là tu entres tout doucement dans l'univers du "tout pour empêcher les autres de faire n'importe quoi avec mon code". Univers dans lequel il y a toujours quelqu'un pour faire n'importe quoi avec le code de quelqu'un d'autre, et où tu finis soit par te pendre, soit par te dire que c'est un peu aux autres de prendre la responsabilité de ce que fait leur code.
    Tu peux prendre quelques précautions là où c'est critique (ok, selon les projets ça peut être très critique un peu partout :), mais inutile de se couper les cheveux en 42 en non-stop, en craignant ce que peuvent faire les autres.


    Bon après c'est comme à chaque fois, tout ça dépend du contexte du projet...

  8. #8
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    C'est pas génialement fait du côté de .NET là. Il faudrait une interface avant IList qui n'ait que des membres en lecture seule. Y a pas, faut faire avec.
    Ok ben il n'y a cas créer sa propre collection.
    Un truc du style :

    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
    61
    62
    63
     
        public class MyList<T> : IListSource, IEnumerable<T>
        {
            private List<T> _List = new List<T>();
     
            #region IListSource Members
     
            public bool ContainsListCollection
            {
                get { return false; }
            }
     
            public IList GetList()
            {
                return _List;
            }
     
            #endregion
     
            public virtual void Add(T item)
            {
                _List.Add(item);
            }
     
            public virtual void Insert(int index, T item)
            {
                _List.Insert(index, item);
            }
     
            public virtual void RemoveAt(int index)
            {
                _List.RemoveAt(index);
            }
     
            public virtual void Remove(T item)
            {
                _List.Remove(item);
            }
     
            public T this[int index]
            {
                get { return _List[index]; }
            }
     
     
            #region IEnumerable<T> Members
     
            public IEnumerator<T> GetEnumerator()
            {
                return _List.GetEnumerator();
            }
     
            #endregion
     
            #region IEnumerable Members
     
            IEnumerator IEnumerable.GetEnumerator()
            {
                return _List.GetEnumerator();
            }
     
            #endregion
        }
    Là au moins les méthodes Add, Remove, RemoveAt et Insert sont virtuelles et l'indexeur et en lecture seule. On peut donc la dériver et contrôler ce qui se passe dans ces méthodes sans que l'utilisateur risque de caster notre collection en une List<T> ou autre.

Discussions similaires

  1. Table Parents-enfants -> conception des objets dans BO 6.1.3
    Par webvince18 dans le forum Designer
    Réponses: 4
    Dernier message: 04/10/2006, 17h27
  2. Problème requête parent/enfant
    Par Bobtop dans le forum Requêtes
    Réponses: 2
    Dernier message: 30/05/2006, 13h07
  3. [.Net] Echange formulaire parents enfants
    Par Arnaud Malabeux dans le forum C++/CLI
    Réponses: 4
    Dernier message: 15/05/2006, 07h59
  4. [.net] Fenêtres parent/enfant
    Par akrodev dans le forum MFC
    Réponses: 1
    Dernier message: 14/04/2006, 23h54
  5. [VB.NET] Problème liste Parent-Enfant dans DataGrid
    Par vonbier dans le forum ASP.NET
    Réponses: 7
    Dernier message: 27/01/2005, 08h53

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