سؤال

لدي ثلاثة فصول. ختم الخطاب والطرد الذي ينفذ منتجًا iProdction ولديهم أيضًا بعض وظائفهم الخاصة.

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

لا يوجد أي نوع من نمط التصميم لهذا النوع من المشاكل. نمط المصنع؟

هل كانت مفيدة؟

المحلول

هذا لأنك تقوم بإلقاء كل عنصر في عربة التسوق كمنتج iProd في حلقة Foreach الخاصة بك. ما يجب عليك فعله هو شيء مثل:

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

نصائح أخرى

لا يمكنك الوصول إلى الأعضاء الإضافيين من الفئات التي تنفذ واجهة لأنك تعرض فقط 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>());
        }
    }
}

لماذا لا يمكنني الوصول إلى الأعضاء الإضافيين من الفصول المشتقة من أ List<IProduct> ?

هذا بسبب، IProduct الواجهة لا تعرف عن UnitPrice, Destination الخ من خصائص الطبقة المشتقة.

هل تحاول إضافة الذكاء لحساب Amount إلى كل من ختم كائنات الفئة المشتقة ، خطاب ، الطرود؟

بعد ذلك ، أود أن أقول إنك بحاجة إلى إعادة تصميم قليلا واستخدام نمط تصميم الديكور.

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

السبب في عدم تمكنك من الوصول إلى أعضاء إضافيين من فئة مشتقة هو أنك تستخدم الواجهة في القائمة <> - وبالتالي ستتمكن فقط من الوصول إلى الخصائص على تلك الواجهة.

نمط قد يساعدك هو نمط dispatch المزدوج.

مثال أدناه:

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

يمكنك الآن برمجة بعض الوظائف المحددة في المعالج - أظن أنك تريد حساب نوع من السعر الإجمالي بالنظر إلى أشياء مثل الكمية * سعر الوحدة أو جدول البحث عن الوزن والوجهة ...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top