Frage

Ich habe drei Klassen; Stempel, Brief und Paket, die ein Schnittstellen -Iprodukt implementieren, und sie haben auch einige ihrer eigenen Funktionen.

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

Warum kann ich nicht auf die zusätzlichen Mitglieder abgeleiteter Klassen von a zugreifen? 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);
}

Ich dachte an die Verwendung von Generika, aber in diesem Fall muss ich für jeden bestimmten Produkttyp separater Code schreiben.

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

Gibt es keine Art von Designmuster für diese Art von Problem? Fabrikmuster?

War es hilfreich?

Lösung

Dies liegt daran, dass Sie jeden Artikel in den Einkaufswagen als iProduct in Ihre Foreach -Schleife werfen. Was Sie tun müssen, ist so etwas wie:

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

Sie wiederholen auch unnötige Eigenschaften Name, Menge und Menge. Sie sollten jedes Ihrer Klassen aus dem Produkt ableiten:

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

Andere Tipps

Sie können nicht auf die zusätzlichen Klassenmitglieder zugreifen, die eine Schnittstelle implementieren, da Sie nur freilegen IProduct in der Liste der Elemente. Ich würde für jeden Artikel im Einkaufswagen spezifische Listentypen in die Einkaufscart -Klasse hinzufügen, und dann können Sie eine Sequenz aller Produkte im Wagen für alles offenbaren, was nur die IPROD -Schnittstelle verwenden muss:

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

Warum kann ich nicht auf die zusätzlichen Mitglieder abgeleiteter Klassen von a zugreifen? List<IProduct> ?

Das ist, weil, IProduct Schnittstelle weiß nichts davon UnitPrice, Destination usw. der abgeleiteten Klasseneigenschaften.

Versuchen Sie, die Intelligenz hinzuzufügen, um die zu berechnen Amount zu jedem der abgeleiteten Klassenobjekte Stempel, Brief, Paket?

Dann würde ich sagen, dass Sie ein wenig neu gestalten und die verwenden müssen Dekorateur Designmuster.

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

Der Grund, warum Sie nicht auf zusätzliche Mitglieder aus einer abgeleiteten Klasse zugreifen können, ist, dass Sie die Schnittstelle in der Liste <> verwenden. Daher können Sie nur auf Eigenschaften dieser Schnittstelle zugreifen.

Ein Muster, das Ihnen helfen könnte, ist das Doppel-Dispatch-Muster.

Beispiel unten:

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

Sie können jetzt einige spezifische Funktionen im Handler programmieren - ich vermute, Sie möchten einen Gesamtpreis berechnen, z. B. Mengen * Einheitspreis oder eine Gewichts- und Ziel -Nachschlagetabelle ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top