2009-06-12 62 views
3

我寫了這個例子來幫助解釋。正如你所看到的,我有一個對象層次結構。我想修改GetFeatures()函數以僅返回由實例化的對象類型的構造函數添加的功能。例如,BasicModel.GetFeatures(new LuxuryModel())應該只返回「皮革座椅」和「天窗」功能。如果必須的話,我不介意使用反射。如何基於創建的子類的類型過濾基類中的對象集合?

Public Class Feature 

    Public Sub New(ByVal model As BasicModel, ByVal description As String) 
     _model = model 
     _description = description 
    End Sub 

    Private _model As BasicModel 
    Public Property Model() As BasicModel 
     Get 
      Return _model 
     End Get 
     Set(ByVal value As BasicModel) 
      _model = value 
     End Set 
    End Property 

    Private _description As String 
    Public Property Description() As String 
     Get 
      Return _description 
     End Get 
     Set(ByVal value As String) 
      _description = value 
     End Set 
    End Property 

End Class 


Public Class BasicModel 
    Public Sub New() 
     _features = New List(Of Feature) 
    End Sub 

    Private _features As List(Of Feature) 

    Public ReadOnly Property Features() As List(Of Feature) 
     Get 
      Return _features 
     End Get 
    End Property 

    Public Shared Function GetFeatures(ByVal model As BasicModel) As List(Of Feature) 
     'I know this is wrong, but something like this...' 
     Return model.Features.FindAll(Function(f) f.Model.GetType() Is model.GetType()) 
    End Function 
End Class 


Public Class SedanModel 
    Inherits BasicModel 

    Public Sub New() 
     MyBase.New() 
     Features.Add(New Feature(Me, "Fuzzy Dice")) 
     Features.Add(New Feature(Me, "Tree Air Freshener")) 
    End Sub 
End Class 


Public Class LuxuryModel 
    Inherits SedanModel 

    Public Sub New() 
     MyBase.New() 
     Features.Add(New Feature(Me, "Leather Seats")) 
     Features.Add(New Feature(Me, "Sunroof")) 
    End Sub 
End Class 

回答

1

如果你想保持當前的層次結構/屬性,只需要創建一個基類的實例,並在派生類中的功能,減去在基類的功能。

或者,您可能需要考慮更改您的類層次結構,以便讓您更容易。

例如,您可以將Features屬性分爲兩個屬性,稱爲ModelFeatures和AllFeatures。

ModelFeatures是特定於當前模型(「Leather Seats」和「天窗」爲LuxuryModel等)。AllFeatures返回MyBase.AllFeatures和ModelFeatures的聯合。這使得獲得當前模型的功能是一個簡單的屬性訪問。

P.S.請原諒我的VB錯誤,C#是我的首選lang。

1

我並不真正熟悉VB.NET的語法,所以這裏是C#語法,應該工作:

public IList<Function> GetFeatures(BasicModel model) 
{ 
    return model.Features.Where(f => f.Model.GetType() == model.GetType()).ToList(); 
} 
+1

在VB中,這並不過濾任何東西。所有功能仍然返回。 – adam0101 2009-06-15 13:29:03

1

(基於上面的示例代碼)

說實話,我不認爲這屬於你的Car Heirachy,在我看來,你希望獲得靜態數據並將你的基類作爲它的容器,並以你的類型作爲關鍵。正如你所看到的,這會導致一些笨拙或過於複雜的編碼。

我會更傾向於把你的靜態數據放在它所屬的地方(在這種情況下)與Feature類本身。我不是一個VB人,所以這段代碼片段在C#中。

所以在要素類本身,有一個靜態屬性(或方法)

public static IEnumerable<Feature> GetLuxuryFeatureSets 
{ 
    get 
    { 
    yield return new Feature() { Name = "Leather Seats" }; 
    yield return new Feature() { Name = "Sunroof" }; 
    } 
} 

,並重復您的其他車型。所以現在你有一個靜態數據的容器,這個類是有意義的。

1

由於無法區分某個功能與另一個功能,因此您需要能夠詢問某個模型添加了哪些功能。而不是你的構造特徵添加到列表中,你應該有一個返回的特定模型添加功能列表的方法...

public class LuxuryModel 
{ 
    public LuxuryModel 
    { 
    Features.Add(GetFeatures()); 
    } 
    public List<Features> GetFeatures() 
    { 
    return new List<Features>(/* new up leather and whatever */ 
    } 
} 

然後,GetFeatures可以做喪氣,並要求其給出的實例對於該特定實例添加功能列表...

public List<Features> GetFeatures<T>(BasicModel model) 
{ 
    var m = Model as T; 
    return m.GetFeatures(); 
} 
1

另一種方式來做到這一點,如果你不想要這個數據是靜態的(見我的對方的回答),你wnat它能夠伸出新類,以及這些類來控制功能集。然後使用多態性(再次C#,因爲我不是VB的傢伙)

在你的基類中創建一個虛函數返回的功能,在你的decenent類重寫屬性,多態性允許你的變量作爲basicmodel類型,只要他們是構造爲後代類型以返回正確的列表。

public class BasicModel 
    { 
    public virtual IEnumerable<Feature> GetFeatures 
    { 
     get 
     { 
     throw new NotImplementedException(); 
     } 
    } 
    } 


    public class LuxuryModel :BasicModel 
    { 
    public override IEnumerable<Feature> GetFeatures 
    { 
     get 
     { 
     yield return new Feature() { Name = "Leather Seats" }; 
     yield return new Feature() { Name = "Sunroof" }; 
     } 
    } 
    } 



private void button1_Click(object sender, EventArgs e) 
{ 
    StringBuilder sb = new StringBuilder(); 

    BasicModel bm = new LuxuryModel(); 

    foreach (Feature f in bm.GetFeatures) 
    { 
    sb.AppendLine(f.Name); 
    } 
    MessageBox.Show(sb.ToString()); 
}