Domanda

Ho tre classi; Timbro, lettere e pacchi che implementano un'interfaccia iProduct e hanno anche alcune delle loro funzionalità.

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

Perché non riesco ad accedere ai membri aggiuntivi delle classi derivate da una 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);
}

Ho pensato di utilizzare farmaci generici, ma in quel caso dovrò scrivere codice separato per ogni tipo di prodotto.

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

Non v'è alcun tipo di modello di progettazione per questo tipo di problema. Modello di fabbrica?

È stato utile?

Soluzione

Questo è perché si sta casting ogni elemento nel carrello della spesa come iProduct nel ciclo foreach. Quello che avrebbe bisogno di fare è qualcosa di simile:

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

Inoltre si sta ripetendo le proprietà inutili Nome, Quantità e Importo . Si dovrebbe derivare ciascuna delle classi di prodotto:

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

Altri suggerimenti

Non è possibile accedere ai membri aggiuntivi delle classi che implementano l'interfaccia perché si sta solo esponendo IProduct nella lista di elementi. Mi piacerebbe aggiungere tipi di liste specifiche per ogni elemento nel carrello della spesa alla classe ShoppingCart, e quindi è possibile esporre una sequenza di tutti i prodotti nel carrello per tutto ciò che ha solo bisogno di utilizzare l'interfaccia 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>());
        }
    }
}
  

Perché non riesco ad accedere al supplementare   membri di classi derivate da una   List<IProduct>?

Questo perché, l'interfaccia IProduct non conosce UnitPrice, Destination ecc delle proprietà classe derivata.

Si sta tentando aggiungere l'intelligenza per calcolare la Amount a ciascuna della classe derivata oggetti Stamp, Lettera, Pacco?

Poi, direi è necessario riprogettare un po 'e utilizzare la Decorator design pattern .

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

Il motivo per cui non è possibile accedere membri aggiuntivi da una classe derivata è che si sta utilizzando l'interfaccia in List <> -. Quindi sarete in solo in grado di accedere alle proprietà su tale interfaccia

Un modello che potrebbe aiutare è il modello a doppia spedizione.

Esempio di seguito:

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

È ora possibile programmare alcune funzionalità specifiche nel gestore - immagino che si desidera calcolare una sorta di prezzo dato totale cose come quantità * prezzo unitario o una tabella di peso e di destinazione del riferimento ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top