2010-08-02 18 views
7

ho una classe astratta BASEITEM dichiarati in questo modo:Utilizzo di farmaci generici in una relazione padre figlio

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

    public abstract string Function1();   
} 

In sostanza, sto cercando di attuare un progetto in cui ogni elemento ha un genitore che sarà di un tipo specifico e i bambini che saranno di un tipo diverso.

Ad esempio, ItemA avrebbe figli di tipo ItemB. Quindi ItemB avrebbe un genitore di tipo ItemA e bambini tutti di tipo ItemC. ItemC avrebbe parent di ItemB e figli di tipo ItemD.

Ho pensato che sarebbe stato più corretto farlo utilizzando i generici per evitare lanci inutili poiché so che tipo genitore e figli saranno per ciascuna delle mie classi ereditate. Quindi mi è venuto in mente qualcosa del genere:

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> 
{ 
} 

Quindi due cose. 1. È un buon design? C'è un modo più semplice/migliore per farlo? Non mi piace usare una seconda classe base astratta solo per poter usare i generici. 2. Se mantengo questo, qual è il modo migliore di gestire i fini? (Cioè Itema non avere un genitore nel mio dominio problema reale, ma ha bisogno di un genitore per la compilazione. ItemD non ha figli, ma ho bisogno di dare qualcosa)

+0

Questa domanda mi fa venire voglia di usare FORTRAN. – iandisme

+0

il tuo esempio di codice ha 'public class ItemC: BaseItem ', ma probabilmente intendevi 'public class ItemC: BaseItem '. –

risposta

1

Se ho capito bene, stai dicendo che ItemA non ha mai un genitore e ItemD non ha mai figli, giusto? Per essere onesti, probabilmente solo dichiarare le classi separate con i propri genitori/bambini proprietà del tipo di destra:

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; } 
} 

L'unica cosa che si sta ripetendo qui è la Parent e Children proprietà/campo. Tutte le altre funzionalità comuni che è possibile implementare nel AbstractBase. (A meno che, naturalmente, questa funzionalità non abbia bisogno di accedere ai genitori/ai figli - ma poi sei tornato al punto di partenza anche nella tua soluzione.)

+0

Accettare la tua risposta perché, alla fine, far funzionare i generici è un sacco di spese generali, non importa in che modo lo faccio, ma con poco beneficio. –

0

Si potrebbe utilizzare due interfacce generiche, ChildOf<T> e IList<T> . Questo ti permetterà di gestire i casi finali. Sfortunatamente dal momento che .NET non ha ereditarietà multipla, non sarai in grado di condividere l'implementazione.

In alternativa è possibile utilizzare la classe astratta e un tipo di marcatore (System.Void sarebbe l'ideale, ma non credo che sarebbe la compilazione) per i casi terminali, e verificare la presenza di esso dai Parent/Children proprietà e un'eccezione .

+0

Puoi sempre usare IoC/DI per iniettare le implementazioni predefinite di entrambe le interfacce – STW

0

Non sembra un'idea troppo brutta, anche se onestamente sarei tentato di mantenere la soluzione originale e sopportare il casting in quanto aggiunge un bel po 'di complessità per non tanto beneficio. (Anche se devo ammettere che cerco di sostituire il casting con i generici ogni volta che posso).

Se avete voglia di tenerlo, un paio di suggerimenti:

  • hanno AbstractBase come interfaccia
  • fare qualcosa di diverso per le estremità (ad esempio due BaseItems extra che prendono un genitore e un bambino generica genere).

Ovviamente, questo secondo punto aggiunge solo alla complessità, che è un'altra ragione per cui non sono sicuro che valga la pena.

1

vorrei fare in questo modo:

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

non vedo un problema con il fare le cose in questo modo, dal momento che sembrano avere una gerarchia specifica che richiede elementi di primo livello ad essere di tipo ItemA, articoli di 2 ° livello per essere di tipo ItemB, ecc

per affrontare i nodi principali e foglia, probabilmente sarei definisco classi separate che derivano anche da 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> 
{ 
} 
Problemi correlati