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 :

Design pattern relation mère-fille


Sujet :

C#

  1. #1
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    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 152
    Points : 7 402
    Points
    7 402
    Billets dans le blog
    1
    Par défaut Design pattern relation mère-fille
    Bonjour,

    J'ai des objets (types différents) qui ont des relations mères filles.

    Par exemple, pour faire l'analogie à une base de données, on a des serveurs, qui hébergent chacuns une ou plusieurs base, qui héberge chacunes une ou plusieurs tables, qui contiennent chacunes une ou plusieurs colonnes.

    Je souhaite savoir quelle prototype utiliser pour pouvoir stocker simplement et proprement la relation entre un objet "fils" et son parent.

    Habituellement je fais un truc du genre :
    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
     
    class Mere
    {
       List<Fille> Filles { get; private set; }
       public Mere() {}
    }
     
    public Fille
    {
        Mere Parent { get; private set; }
        public Fille(Mere mere)
        {
            Parent = mere;
        }
    }

    Mais je trouve ça contraignant (constructeur alourdi inutilement).

    J'aimerais par exemple surcharger le List<Fille>.Add() pour effectuer ce rattachement, mais sans exposer de méthode SetParent() de manière publique : je n'ai pas envie de pouvoir changer de parent depuis ailleurs.

    Aussi, je voudrais pouvoir empêcher de faire :
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    mere2.Filles[1] = mere1.Filles[5];

    mere1.Filles[5] a déjà une mère, et je ne veux pas qu'elle puis changer en cours de route, ni que mere2 contienne des filles qui ne lui appartiennent pas.

    En se lançant dans des usines à gaz avec redéfinition des accesseurs et création de classes de collections dédiées, y'a probablement moyen de s'en sortir, mais n'existe-t-il pas un design pattern simple pour gérer ça ?
    On ne jouit bien que de ce qu’on partage.

  2. #2
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    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 152
    Points : 7 402
    Points
    7 402
    Billets dans le blog
    1
    Par défaut
    Voici ce que je cherche à faire (probablement incomplet).

    Le but serait de trouver un truc plus simple à gérer...

    D'autant par exemple qu'ici je ne peux pas avoir une class qui est à la fois Child et Parent... Ou alors il faut créer une autre classe abstraite pour gérer ce type de classe intermédiaire...

    Child.cs
    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
     
    using System;
     
    namespace ParentChildPattern
    {
        public abstract class Child
        {
            public Parent Parent { get; private set; }
     
            public Child()
            {
                // Nothing
            }
     
            public void SetParent(Parent parent)
            {
                if (Parent is null)
                {
                    Parent = parent;
                }
                else
                {
                    throw new InvalidOperationException("This child already has a parent");
                }
            }
     
            public void RemoveParent()
            {
                Parent = null;
            }
        }
    }

    Parent.cs
    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
     
    using System;
    using System.Collections;
    using System.Collections.Generic;
     
    namespace ParentChildPattern
    {
        public abstract class Parent : IList<Child>
        {
            private List<Child> Children { get; set; }
     
            public int Count => Children.Count;
     
            public bool IsReadOnly => false;
     
            public Parent()
            {
                Children = new List<Child>();
            }
     
            public Parent(List<Child> children)
            {
                children.ForEach(a => a.SetParent(this));
                Children = children;
            }
     
            public Child this[int i]
            {
                get
                {
                    return Children[i];
                }
                set
                {
                    if (value is null)
                    {
                        Children[i].RemoveParent();
                    }
                    else if (value.Parent is null)
                    {
                        value.SetParent(this);
                    }
                    else if (value.Parent != this)
                    {
                        throw new InvalidOperationException("Impossible to add a child that belongs to another parent");
                    }
     
                    Children[i] = value;
                }
            }
     
            public int IndexOf(Child item)
            {
                return Children.IndexOf(item);
            }
     
            public void Insert(int index, Child item)
            {
                if (item is null)
                {
                    Children[index].RemoveParent();
                }
                else if (item.Parent is null)
                {
                    item.SetParent(this);
                }
                else if (item.Parent != this)
                {
                    throw new InvalidOperationException("Impossible to add a child that belongs to another parent");
                }
     
                Children.Insert(index, item);
            }
     
            public void RemoveAt(int index)
            {
                Children[index].RemoveParent();
                Children.RemoveAt(index);
            }
     
            public void Add(Child item)
            {
                if (item.Parent is null)
                {
                    item.SetParent(this);
                }
                else if (item.Parent != this)
                {
                    throw new InvalidOperationException("Impossible to add a child that belongs to another parent");
                }
     
                Children.Add(item);
            }
     
            public void Clear()
            {
                Children.ForEach(a => a.RemoveParent());
                Children.Clear();
            }
     
            public bool Contains(Child item)
            {
                return Children.Contains(item);
            }
     
            public void CopyTo(Child[] array, int arrayIndex)
            {
                Children.CopyTo(array, arrayIndex);
            }
     
            public bool Remove(Child item)
            {
                item.RemoveParent();
                return Children.Remove(item);
            }
     
            public IEnumerator<Child> GetEnumerator()
            {
                return Children.GetEnumerator();
            }
     
            IEnumerator IEnumerable.GetEnumerator()
            {
                return Children.GetEnumerator();
            }
        }
    }

    Et enfin, program.cs
    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
     
    using ParentChildPattern;
     
    namespace Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                Table t1 = new Table() { Name = "Table 1" };
                Table t2 = new Table() { Name = "Table 2" };
     
                t1.Add(new Field() { Name = "ID" });
                t1.Add(new Field() { Name = "Label" });
     
                //t2.Add(t1[0]);  //<-- Will fail
     
                Child child = t1[0];
                t1.RemoveAt(0);
                t2.Add(child);    //<-- Will work
                //t1.Add(child);  //<-- Will fail
            }
        }
     
        public class Table : Parent
        {
            public string Name { get; set; }
        }
     
        public class Field : Child
        {
            public string Name { get; set; }
        }
    }
    On ne jouit bien que de ce qu’on partage.

  3. #3
    Expert éminent sénior

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

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

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 697
    Points
    10 697
    Billets dans le blog
    21
    Par défaut
    Bonjour,

    Pour ma part, l'idée me semble bonne. Si tes classes Child et Parent sont dans un projet à part, je changerai la visibilité de SetParent en internal, histoire qu'il ne soit pas accessible depuis l'extérieur (ou protected internal pour qu'il soit aussi accessible aux classes dérivées si besoin est).

    Attention aussi au constructeur de la classe Parent qui accepte une liste en paramètre, il y a un bug potentiel : si un des enfants à déjà un parent, une exception sera générée au moment de l'appel à sa méthode SetParent. C'est à dire que les éléments enfants avant dans la liste seront affectée à la liste en cours de définition, mais qui ne sera jamais accessible à cause d'une exception dans le constructeur ! Du coup, des enfants peuvent se retrouver avec un parent non défini... (bon, cas tordu, je le concède, car il faudra une liste d'enfants avec et sans parent).
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  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

    Composite Pattern est ton ami . Une interface commune et IEnumerable<toninterface> qui ne permet d'ecrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     instance.children[i] =  value;
    code exemple :
    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
    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
     
    public  interface IData
        {
            string Name { get; set; }
        }
     
    // Class  racine
    public class Server : IData, IEnumerable<IData>
        {  
            private List<IData> _children = new List<IData>();
     
            public string Name { get; set; }
     
            public Server(string name)
            {
                Name = name;
            }
     
            public void AddChild(IData child)
            {
                _children.Add(child);
            }
     
            public void RemoveChild(IData child)
            {
                _children.Remove(child);
            }
     
            public IData GetChild(int index)
            {
                return _children[index];
            }
     
            public IData GetChild(string name)
            {
                return _children.Where(c => c.Name == name).First();
            }
     
            public IEnumerable<IData> GetChildren()
            {
                return _children;
            }
            public IEnumerator<IData> GetEnumerator()
            {
                return ((IEnumerable<IData>)_children).GetEnumerator();
            }
     
            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IEnumerable<IData>)_children).GetEnumerator();
            }
        }
     
    //  Class  Enfant1
      public class DataBase : IData, IEnumerable<IData>
        {
            private List<IData> _children = new List<IData>();
     
            public string Name { get; set; }
     
            public DataBase(string name)
            {
                Name = name;
            }
     
            public void AddChild(IData child)
            {
                _children.Add(child);
            }
     
            public void RemoveChild(IData child)
            {
                _children.Remove(child);
            }
     
            public IData GetChild(int index)
            {
                return _children[index];
            }
     
            public IData GetChild(string name)
            {
                return _children.Where(c => c.Name == name).First();
            }
     
            public IEnumerable<IData> GetChildren()
            {
                return _children;
            }
            public IEnumerator<IData> GetEnumerator()
            {
                return ((IEnumerable<IData>)_children).GetEnumerator();
            }
     
            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IEnumerable<IData>)_children).GetEnumerator();
            }
        }
     
     
    // Class Enfant2
     public class Table : IData, IEnumerable<IData>
        { 
            private List<IData> _children = new List<IData>();
     
            public string Name { get; set; }
     
            public Table(string name)
            {
                Name = name;
            }
     
            etc...
     
    }
     // Class  Enfant3
     public class Column : IData, IEnumerable<IData>
        {
            private List<IData> _children = new List<IData>();
     
            public string Name { get; set; }
     
            public Column(string name)
            {
                Name = name;
            }
    }
     
    // Class enfant4
    ..............................Etc.
    bon code...

Discussions similaires

  1. [AC-2010] relation "mère-fille" 0-N
    Par weyb06 dans le forum Modélisation
    Réponses: 6
    Dernier message: 23/03/2018, 15h28
  2. [2.x] Relation entité et/ou design pattern
    Par deezpowned dans le forum Symfony
    Réponses: 7
    Dernier message: 12/12/2014, 15h49
  3. Rapport Redmine avec relation mère-fille
    Par spud16 dans le forum Gestion de projet
    Réponses: 0
    Dernier message: 01/07/2013, 17h06
  4. Réponses: 4
    Dernier message: 24/02/2009, 12h06
  5. Interbase - DBExpress - relation mère/fille
    Par indiana64 dans le forum Bases de données
    Réponses: 8
    Dernier message: 13/03/2007, 14h57

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