2010-01-28 10 views
6

Me preguntaba cuál de las siguientes opciones se considera una mejor práctica cuando se trata de relaciones entre padres e hijos.Diseño dirigido por el dominio - Patrón de relación padre-hijo - Patrón de especificación

1) El siguiente ejemplo parece ser una práctica común, pero al crear una instancia de un elemento secundario, estará en un estado no válido siempre que no se agregue al elemento primario. No ¿Puede esto conducir a problemas relacionados con la validación etc.

public class Parent 
{ 
    private ICollection<Child> children; 

    public ReadOnlyCollection Children { get; } 

    public void AddChild(Child child) 
    { 
     child.Parent = this; 
     children.Add(child); 
    } 
} 


public class Child 
{ 
    internal Parent Parent 
    { 
     get; 
     set; 
    } 

    public Child() 
    { 
    } 
} 

2) La siguiente muestra se encargaría de que un niño siempre debe estar relacionada con su matriz.

public class Parent 
{ 
    private ICollection<Child> children; 

    public ReadOnlyCollection Children { get; } 

    public Child CreateChild() 
    { 
     var child = new Child(); 
     child.Parent = this; 
     children.Add(child); 
     return child; 
    } 
} 


public class Child 
{ 
    internal Parent Parent 
    { 
     get; 
     set; 
    } 

    internal Child() 
    { 
    } 
} 

3) En el último ejemplo, ese niño se ocupa de la relación con su propio padre.

public class Parent 
{ 
    private ICollection<Child> children; 

    public ReadOnlyCollection Children { get; } 

    public void AddChild(Child child) 
    { 
     child.Parent = this; 
     children.Add(child); 
    } 
} 


public class Child 
{ 
    public Parent Parent 
    { 
     get; 
     set; 
    } 

    public Child(Parent parent) 
    { 
     this.Parent = parent; 
    } 
} 

¿Qué patrón se considera el mejor? Creo que el patrón 2 podría ser el mejor, ya que un niño nunca puede existir sin una relación con su padre. Esto lo haría más fácil, por ej. al implementar un patrón de especificación que podría hacer cosas como:

public class ChildSpecification 
{ 
    bool IsSatisfiedBy(Child child) 
    { 
     return child.Parent.Children.Where(someCondition).Count > 0; 
    } 
} 

La especificación anterior solo puede funcionar si un niño tiene un elemento primario.

¿Qué opinas? ¿Conoces mejores maneras? Gracias de antemano

Respuesta

0

Tiendo a usar la opción (1) - siempre me ha funcionado bien. Lo importante es no exponer la colección de los niños mismos al mundo exterior: el padre debe ser capaz de mediar en todo el acceso. Pero estoy perfectamente feliz de que un niño sea creado en otro lugar; solo me importa cuando se agrega al padre, y en este punto se puede verificar su validez, etc.

No entiendo su ejemplo de especificación: parece que su ChildSpecification volvería verdadera si cualquier de los hijos del padre tiene alguna condición como verdadera. Seguramente IsSatisfiedBy (Niño) solo debe devolver verdadero si el elemento secundario específico pasó como un parámetro que cumple la condición.

+0

El patrón de especificación trata de un caso especial que tengo actualmente en uno de mis proyectos. Un niño tiene un intervalo de fechas de validez, que no debe coincidir con ningún otro intervalo de fechas de validez de ningún otro niño dentro de la colección de niños. ¿Consideraría esto una especificación para el padre? – Chris

+0

Probablemente implementaría esto como una condición de protección en el método addChild() de Parent. El padre entonces no permitiría el agregado, p. lanzando una excepción. Probablemente no usaría una especificación en este caso. – alasdairg

+0

Pero también debo verificarlo en la UI. Entonces, cuando se lanza una excepción, tendría que atrapar eso. Esto tampoco es muy elegante. Y afaik lo bueno de las especificaciones es que podría usarlo en muchos escenarios diferentes, como 1.) dentro de mi dominio oe 2.) dentro de una aplicación cliente para validar previamente la lógica comercial. ¿O estoy equivocado? – Chris

5

Definitivamente me gusta la sugerencia número 2, pero yo creo que se echa de menos algo importante que se encuentra en 3, a saber, que si un objeto Child no puede existir sin un Parent que debe tomar un objeto Parent en su constructor. Además, la propiedad Parent en la clase Child debe ser de solo lectura. Por lo que terminaría con algo como:

public class Parent 
{ 
    private ICollection<Child> children; 

    public ReadOnlyCollection Children { get; } 

    public Child CreateChild() 
    { 
     var child = new Child(this); 
     children.Add(child); 
     return child; 
    } 
} 


public class Child 
{ 
    internal Parent Parent 
    { 
     get; 
     private set; 
    } 

    internal Child(Parent parent) 
    { 
     this.Parent = parent; 
    } 
} 
+0

También lo haría así, si la especificación es que un niño siempre debe tener un padre, y no se puede crear sin conocer a su padre. Entonces, solo una combinación de 2 y 3. +1 –

1

Desde que he encontrado el mismo solo desissions diseño y pregunta todavía no marcadas como respondí voy a publicar mi visión en la solución de este problema - tal vez va ayudar a alguien Esta solución realmente es perfectamente viable para usar con NHibernate.

public class Parent 
{ 
    private readonly ISet<Child> _children = new HashedSet<Child>(); 
    public virtual IEnumerable<Child> Children { get { return new ImmutableSet<Child> (this._children); } } 


    protected internal virtual void AddChild (Child child) 
    { 
     this._children.Add(child); 
    } 
} 


public class Child 
{ 
    public virtual Parent Parent { get; protected set; } 


    protected Child() 
    { 
    } 


    public static Create (Parent parent) 
    { 
     if (parent == null) 
      throw new ArgumentNullException ("parent"); 

     var child = new Child 
     { 
      Parent = parent 
     }; 

     child.Parent.AddChild (child); 

     return child; 
    } 
} 

Eso es difiere de su opción # 2 de manera que la creación del objeto secundario (e invalidar su valor inicial) están reunidos withing objeto hijo en sí y no en objeto padre como usted sugiere en 2 #.

Una cosa más No estoy seguro si se considera un diseño malo o no si creamos objetos secundarios con el método de fábrica personal (Child.Create).

Espero que alguien con más experiencia en el uso de DDD pueda comentar sobre eso.

Cuestiones relacionadas