2010-08-02 39 views
7

我有一個抽象類BaseItem聲明如下:在父子關係中使用泛型

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

    public abstract string Function1();   
} 

基本上,我試圖實現設計,其中每個項目有一個家長,這將是一種特定類型的和將是不同類型的兒童。

例如,ItemA會讓孩子都是ItemB類型。然後,ItemB將具有ItemA類型的父項,並且具有所有ItemC類型的子項。 ItemC將具有ItemB的父項和ItemD類型的子項。

我認爲使用泛型來避免不必要的轉換會更簡單,因爲我知道每個繼承類的父類和子類都是什麼類型。所以我想出了這樣的事情:

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

所以兩件事。 1.這是一個很好的設計嗎?有沒有更簡單/更好的方法?我真的不喜歡使用第二個抽象基類只是爲了能夠使用泛型。 2.如果我確實保留這個,處理結尾的最好方法是什麼? (即ItemA在我的實際問題域中沒有父項,但它需要一個父項來編譯。ItemD沒有子項,但我需要給它一些東西)

+0

這個問題讓我想使用FORTRAN。 – iandisme 2010-08-02 15:40:25

+0

您的代碼示例具有'公共類ItemC:BaseItem ',但您可能是指公共類ItemC:BaseItem '。 – 2010-08-02 17:05:30

回答

1

如果我理解你是對的,你說ItemA從來沒有父母和ItemD從來沒有任何孩子,對吧?說實話,我很可能只是正確類型的自己的父母/子女性能聲明獨立的類:

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

你重複這裏唯一的事情是ParentChildren屬性/字段。您可以在AbstractBase中實現的所有其他常用功能。 (當然,除非該功能需要訪問父母/子女 - 但是即使在您的解決方案中,您也可以回到原來的位置。)

+0

接受您的答案是因爲最終,要使泛型能夠正常工作,無論我採用哪種方式進行操作都會產生大量開銷,但收效甚微。 – 2010-08-03 13:18:51

0

您可能使用兩個通用接口ChildOf<T>IList<T> 。這會讓你處理最終情況。不幸的是,由於.NET沒有多重繼承,你將無法共享實現。

另外,您可以使用抽象類和標識類型(System.Void將是理想的,但我不認爲它會編譯)爲結束的情況下,從Parent/Children性能檢查,並拋出一個異常。

+0

您可以隨時使用IoC/DI來注入兩個接口的默認實現。 – STW 2010-08-02 15:47:24

0

這似乎不是太糟糕的想法,但說實話我會試圖保持原來的解決方案,並與演員混在一起,因爲它確實增加了一點複雜性,沒有那麼多好處。 (儘管我必須承認我會盡可能地用泛型替換鑄件)。

如果你確實想保持它,一對夫婦的建議:

  • 有AbstractBase作爲接口
  • 做一些事情的結束(這需要父母和孩子一般的如兩個額外BaseItems不同類型)。

很明顯,這第二點只會增加複雜性,這是我不確定這是否值得的另一個原因。

1

我會做這樣的:

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

我看不出這樣做,讓一個問題,因爲你似乎有需要頂級項目是類型的特定層次結構ItemA,第二級項是ItemB類型等

爲了解決根和葉節點,我可能限定單獨的類也從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> 
{ 
}