2010-08-02 14 views
7

que tengo una clase abstracta artículo base declarados como esto:Uso de los genéricos en una relación padre-hijo

public abstract class BaseItem 
{ 
    public BaseItem Parent { get; protected set; } 
    public List<BaseItem> Children = new List<BaseItem>(); 

    public abstract string Function1();   
} 

Básicamente, estoy tratando de implementar un diseño en el que cada artículo tiene un padre que será de un tipo específico y niños que serán de un tipo diferente.

Por ejemplo, ITEMA tendría los niños de todo tipo de ItemB. Entonces, ItemB tendría un elemento primario de tipo ItemA y elementos secundarios de tipo ItemC. ItemC tendría el padre del ItemB y los hijos del tipo ItemD.

pensé que sería más ordenado a hacerlo usando genéricos para evitar moldes innecesarios ya que sé qué tipo es el padre y los hijos serán para cada una de mis clases heredadas. Así que se me ocurrió algo como esto:

public abstract class AbstractBase 
{ 
    public abstract string Function1(); 
} 

public abstract class BaseItem<T1, T2> : AbstractBase 
    where T1 : AbstractBase 
    where T2 : AbstractBase 
{ 
    public T1 Parent { get; protected set; } 
    public List<T2> Children = new List<T2>(); 
} 

public class ItemA : BaseItem<ItemA, ItemB> 
{ 
} 
public class ItemB : BaseItem<ItemA, ItemC> 
{ 
} 
public class ItemC : BaseItem<ItemB, ItemD> 
{ 
} 
public class ItemD : BaseItem<ItemC, ItemD> 
{ 
} 

Dos cosas. 1. ¿Es este un buen diseño? ¿Hay una manera más simple/mejor de hacer esto? Realmente no me gusta usar una segunda clase base abstracta solo para poder usar genéricos. 2. Si guardo esto, ¿cuál es la mejor manera de manejar los extremos? (es decir, ItemA no tiene un padre en mi dominio de problema real, pero necesita un padre para compilar. ItemD no tiene hijos, pero necesito darle algo)

+0

Esta pregunta me hace querer usar FORTRAN. – iandisme

+0

su ejemplo de código tiene 'clase pública ItemC: BaseItem ', pero probablemente significó 'clase pública ItemC: BaseItem '. –

Respuesta

1

Si entiendo bien, usted está diciendo que ItemA nunca tiene un padre y ItemD nunca tiene hijos, ¿verdad? Para ser honesto, probablemente me acaba de declarar las clases separadas con sus niños/propiedades propio padre del tipo correcto:

public abstract class AbstractBase 
{ 
    public abstract string Function1(); 
} 

public class ItemA : AbstractBase 
{ 
    public List<ItemB> Children = new List<ItemB>(); 
} 
public class ItemB : AbstractBase 
{ 
    public ItemA Parent { get; protected set; } 
    public List<ItemC> Children = new List<ItemC>(); 
} 
public class ItemC : AbstractBase 
{ 
    public ItemB Parent { get; protected set; } 
    public List<ItemD> Children = new List<ItemD>(); 
} 
public class ItemD : AbstractBase 
{ 
    public ItemC Parent { get; protected set; } 
} 

Lo único que se está repitiendo aquí es el Parent y Children propiedad/campo. Todas las demás funciones comunes que puede implementar en el AbstractBase. (A menos que, por supuesto, esa funcionalidad necesite acceso a los padres/hijos, pero luego vuelves al punto de partida incluso en tu solución.)

+0

Aceptando su respuesta porque, al final, lograr que los genéricos funcionen es una gran cantidad de sobrecarga sin importar de qué manera lo haga, pero con poco beneficio. –

0

Puede utilizar dos interfaces genéricas, ChildOf<T> y IList<T> . Esto le permitirá manejar los casos finales. Desafortunadamente, dado que .NET no tiene herencia múltiple, no podrá compartir la implementación.

otra posibilidad es utilizar la clase abstracta y un tipo de marcador (System.Void sería lo ideal, pero no creo que sería compilar) para los casos extremos, y comprobar para ella de las Parent/Children propiedades y lanza una excepción .

+0

Siempre puede usar IoC/DI para inyectar implementaciones predeterminadas de ambas interfaces – STW

0

No parece una idea demasiado mala, aunque para ser sincero, estaría tentado de mantener la solución original y soportar el casting, ya que agrega un poco de complejidad para obtener no tanto beneficio. (Aunque debo admitir que trato de reemplazar el casting con genéricos siempre que puedo).

Si quería mantenerlo, un par de sugerencias:

  • tienen AbstractBase como una interfaz
  • hacer algo diferente para los extremos (por ejemplo, dos BaseItems adicionales que tienen un padre y un hijo genérica tipo).

Obviamente, este segundo punto solo se suma a la complejidad, que es otra razón por la que no estoy seguro de que valga la pena.

1

lo haría así:

public interface IChildOf<T> { 
    T Parent { get; set; } 
} 

public interface IParent<T> { 
    List<T> Children { get; set; } 
} 

//This class handles all of the cases that have both parent and children 
public abstract class BaseItem<T1, T2> : IParent<T1>, IChildOf<T2> 
{ 
    public List<T1> Children { get; set; } 
    public T2 Parent { get; set; } 
} 

//This class handles the top level parent 
public class ItemA : IParent<ItemB> 
{ 
    public List<ItemB> Children { get; set; } 
} 
public class ItemB : BaseItem<ItemC, ItemA> 
{ 
} 
public class ItemC : BaseItem<ItemD, ItemB> 
{ 
} 
//.... as many intermediates as you like. 

//This class handles the bottom level items with no children 
public class ItemD : IChildOf<ItemC> 
{ 
    public ItemC Parent { get; set; } 
} 
0

no veo un problema con hacer las cosas de esta manera, ya que parecen tener una jerarquía específica que requiere de elementos de nivel superior para ser de tipo ItemA, artículos de segundo nivel para ser de tipo ItemB, etc.

para hacer frente a los nodos raíz y las hojas, probablemente me defino clases separadas, que también se derivan de AbstractBase:

public abstract class RootItem<T2> : AbstractBase 
    where T2 : AbstractBase 
{ 
    public List<T2> Children = new List<T2>(); 
} 

public abstract class LeafItem<T1> : AbstractBase 
    where T1 : AbstractBase 
{ 
    public T1 Parent { get; protected set; } 
} 

public class ItemA : RootItem<ItemB> 
{ 
} 
public class ItemB : BaseItem<ItemA, ItemC> 
{ 
} 
public class ItemC : BaseItem<ItemB, ItemD> 
{ 
} 
public class ItemD : LeafItem<ItemC> 
{ 
} 
Cuestiones relacionadas