2009-11-23 61 views
0

我有三個班;實現接口IProduct的郵票,信件和包裹,他們也有自己的一些功能。如何從界面訪問派生類成員?

public interface IProduct 
{ 
    string Name { get; } 
    int Quantity { get; set; } 
    float Amount { get; } 
} 

public class Stamp : IProduct 
{ 
    public string Name { get { return "Stamp"; } } 
    public int Quantity { get; set; } 
    public float Amount { get; set; } 
    public float UnitPrice { get; set; } 
} 

public class Letter : IProduct 
{ 
    public string Name { get { return "Letter"; } } 
    public int Quantity { get; set; }   
    public float Amount { get; set; } 
    public float Weight { get; set; } 
    public string Destination { get; set; } 
} 

public class Parcel : IProduct 
{ 
    public string Name { get { return "Parcel"; } } 
    public int Quantity { get; set; }   
    public float Amount { get; set; } 
    public float Weight { get; set; } 
    public string Destination { get; set; } 
    public int Size { get; set; } 
} 

public static class ShoppingCart 
{ 
    private static List<IProduct> products = new List<IProduct>(); 
    public static List<IProduct> Items { get { return products; } } 
} 

爲什麼我不能訪問派生類的其他成員從List<IProduct>

ShoppingCart.Items.Add(new Stamp { Quantity = 5, UnitPrice = 10, Amount = 50 }); 
ShoppingCart.Items.Add(new Letter { Destination = "US", Quantity = 1, Weight = 3.5f }); 
ShoppingCart.Items.Add(new Parcel { Destination = "UK", Quantity = 3, Weight = 4.2f, Size = 5 }); 

foreach (IProduct product in ShoppingCart.Items) 
{ 
    Console.WriteLine("Name: {0}, Quantity: {1}, Amount: {2}", product.Name, product.Quantity, product.Amount); 
} 

我想使用泛型的,但在這種情況下,我將必須編寫單獨的代碼對於每個特定類型的產品。

public static class ShoppingCart<T> where T : IProduct 
{ 
    private static List<T> items = new List<T>(); 
    public static List<T> Items { get { return items; } } 
} 


ShoppingCart<Stamp>.Items.Add(new Stamp { Quantity = 5, Amount = 10, UnitPrice = 50 }); 
ShoppingCart<Letter>.Items.Add(new Letter { Destination = "US", Quantity = 1, Weight = 3.5f }); 

foreach (Stamp s in ShoppingCart<Stamp>.Items) 
{ 
    Console.WriteLine("Name: {0}, Quantity: {1}, Amount: {2}", s.Name, s.Quantity, s.Amount); 
} 

foreach (Letter l in ShoppingCart<Letter>.Items) 
{ 
    Console.WriteLine("Name: {0}, Destination: {1}, Weight: {2}", l.Name, l.Destination, l.Weight);  
} 

這種問題沒有任何一種設計模式。工廠模式?

+0

我的問題是你的接口的要點是什麼,如果它只有成員而不是方法?你只是在每個班級重新定義這些成員。 – JonH 2009-11-23 13:12:02

+0

接口有必要有方法嗎? – 2009-11-23 13:16:42

+0

不,這不是必要的,但通常你使用接口來遵守合同。合同通常是需要通過簽署合同的類來實施的方法。在簽名者必須實現它們的界面中有方法時。當談到變量本身,只有變量纔有意義創建一個接口? – JonH 2009-11-23 13:18:29

回答

1

這是因爲您正在將購物車中的每個商品作爲您的foreach循環中的IProduct進行投射。什麼,你需要做的是一樣的東西:

foreach(IProduct product in ShoppingCart.Items) 
{ 
    if (product is Stamp) 
    { 
     var stamp = product as Stamp; 
     Console.WriteLine("Name: {0}, Quantity: {1}, Amount: {2}, UnitPrice: {3}", stamp.Name, stamp.Quantity, stamp.Amount, stamp.UnitPrice); 
    } 
    else if (product is Letter) 
    { 
     var letter = product as Letter; 
     Console.WriteLine("Name: {0}, Quantity: {1}, Amount: {2}, Weight: {3}, Destination: {4}", letter.Name, letter.Quantity, letter.Amount, letter.Weight, letter.Destination); 
    } 
    else if (product is Parcel) 
    { 
     var parcel = product as Parcel; 
     Console.WriteLine("Name: {0}, Quantity: {1}, Amount: {2}, Weight: {3}, Destination: {4}, Size: {5}", parcel.Name, parcel.Quantity, parcel.Amount, parcel.Weight, parcel.Destination, parcel.Size); 
    } 
} 

你也正在重複不必要的性能名稱,數量及金額。你應該從產品派生你的每一個類:

public class Stamp: Product, IProduct 
{ 
    public double UnitPrice { get; set; } 
} 

public class TransitProduct: Product, IProduct 
{ 
    public double Weight { get; set; } 
    public string Destination { get; set; } 
} 

public class Letter: TransitProduct, IProduct 
{ 
} 

public class Parcel: TransitProduct, IProduct 
{ 
    public double Size { get; set; } 
} 
1

您無法從派生類訪問額外成員的原因是您正在使用列表<>中的界面 - 因此您只能訪問該界面上的屬性。

可能對您有幫助的模式是雙派遣模式。

下例:

public interface IHandler 
{ 
    void Handle(Stamp stamp); 
    void Handle(Letter letter); 
    ... 
} 

public class Handler : IHandler 
{ 
    public void Handle(Stamp stamp) 
    { 
     // do some specific thing here... 
    } 
    public void Handle(Letter letter) 
    { 
     // do some specific thing here... 
    } 
    ... 
} 

public interface IProduct 
{ 
    string Name { get; } 
    int Quantity { get; set; } 
    float Amount { get; } 
    void Handle(IHandler handler); 
} 

public class Stamp : IProduct 
{ 
    public string Name { get { return "Stamp"; } } 
    public int Quantity { get; set; } 
    public float Amount { get; set; } 
    public float UnitPrice { get; set; } 
    public void Handle(IHandler handler) 
    { 
     handler.Handle(this); 
    } 
} 

您現在可以進行編程的處理程序某些特定的功能 - 我猜你要計算某種價格定的總的東西,如數量*單價或重量&目的地查找表...

+0

感謝Codebrain。你可以在C#中提供任何示例/鏈接或雙重調度模式嗎? – 2009-11-23 13:10:29

+0

不錯的Codebrain。謝謝:) – 2009-11-23 13:38:15

1

爲什麼我不能訪問派生類的附加 成員從 List<IProduct>

這是因爲,IProduct接口不知道UnitPriceDestination等派生類的屬性。

您是否試圖添加智能來計算Amount到每個派生類對象Stamp,Letter,Parcel?

然後,我會說你需要重新設計一點,並使用Decorator design pattern

DerivedClass::Amount() 
{ 
    Base::Amount() + 
    //Amount logic based on derived class 
} 
2

您不能訪問的,其實現的接口,因爲你只有在項目列表中暴露IProduct類的其他成員。我要補充具體名單類型在購物車到我的購物類中的每個項目,那麼您可以在任何東西的車只需要使用IProduct接口暴露的所有產品的序列:

public class ShoppingCart 
{ 
    public IList<Stamp> Stamps { get; } 
    public IList<Letter> Letters { get; } 
    public IList<Parcel> Parcels { get; } 

    public IEnumerable<IProduct> Products 
    { 
     get 
     { 
      return this.Stamps.Cast<IProduct>() 
       .Concat(this.Letters.Cast<IProduct>()) 
       .Concat(this.Parcels.Cast<IProduct>()); 
     } 
    } 
} 
+0

使用OfType <>擴展名可以實現相同嗎? – 2009-11-23 13:19:45

+0

是的,但在這種情況下效果會相同 – Lee 2009-11-23 13:46:03