سؤال

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

أنا بحاجة إلى مساعدة أساسا لأن ما فعلته يشعر فوضوي ولكن لا أستطيع التفكير في حل آخر يعمل بشكل أفضل.

لدي فئة تسمى MudObject, و فئة أخرى تسمى Container, وعاء يمكن أن تحتوي على عدة MudObjects, لكن هو MudObject نفسها, ومع ذلك MudObjects بحاجة إلى معرفة ما هي الواردة في.

حتى تبدو شيئا مثل هذا:

public abstract class MudObject
{
    Container containedBy;
}

public abstract class Container : MudObject
{
    List<MudObject> Contains;
}

(يرجى ملاحظة أن هذه هي فقط على سبيل المثال و بعض التصفيات والوصول إلى المعدلات ، خصائص هذا غاب عن إيقاف)

الآن فقط وهذا في حد ذاته يبدو فوضوي ، ولكن يتيح إضافة شيء آخر إلى المزيج:

Item هو MudObject أن جميع العناصر البصرية (مثل الأسلحة) سوف تكون موروثة من ذلك بعض هذه تحتاج إلى أن تكون حاويات جدا (مثل صدورهم).ولكن لا يوجد مثل وراثة متعددة في c#, حتى أنه يأتي إلى أسفل إلى واجهات سيكون أفضل خيار لجعل الحاوية واجهة (بقدر ما أستطيع أن أرى) ومع ذلك كان هناك سبب لم أكن أريد لها أن تكون ، على أن يتم ذلك بإضافة MudObject إلى حاوية سوف يسبب الحاوية على تحديث MudObjects .containedBy القيمة.

أي الأفكار التي من شأنها أن تجعل هذا العمل ، أو أنا الوقوع في فخ جعل الأمور أكثر تعقيدا ؟
إذا ماذا تقترح ؟

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

المحلول

ما تطلبه هو معقول ، مركب تصميم نمط

نصائح أخرى

وأعتقد أنك overcomplicating. إذا MudObjects يمكن أن تحتوي MudObjects البعض، الطبقة قاعدة واحدة تحتاج ينبغي أن يكون على طول هذه الخطوط:

public abstract class MudObject
{    
    MudObject containedBy; //technically Parent
    List<MudObject> Contains; //children
}

وهذا هو مماثل لطريقة WinForms عناصر ويعمل ASP.NET. العديد من الضوابط الحاوية على حد سواء والضوابط، ويمكن أن تحتوي على مجموعة من subcontrols.

ما تريده هو معقول جدا:إنه لا يختلف عن ويندوز عناصر تحكم النموذج الذي يمكن أن يكون في حد ذاته وعاء يحتوي على عناصر تحكم أخرى.

ما عليك القيام به هو إنشاء الخاصة بك تنفيذ List<MudObject>:

public class MudObjectList : List<MudObject>

الذي ينفذ ، من بين أمور أخرى ، إضافة وظيفة:

public void new Add(MudObject obj)
{
    obj.ContainedBy = this;
    base.Add(obj);
}

ملاحظة:هذا الأسلوب الظلال بدلا من تجاوزات القديمة إضافة وظائف

بهذه الطريقة يمكنك على الفور ملء ContainedBy السمة على إضافة.بالطبع هذا يعني ضمنا أن ContainedBy يمكن null, مما يعني أن هذا هو أعلى مستوى الكائن.

أخيرا, أنا لا أعتقد أن هناك حاجة إلى جعل مستقل MudObject و Container فصول ، حيث كونها وعاء يبدو الذاتية إلى MudObject (ff تستخدم C# 3.0 التلقائي الخصائص):

public abstract class MudObject
{
    MudObject ContainedBy { get; set; }
    MudObjectList Contains { get; set; }
}

لماذا لا تجعل جميع الحاويات MudObjects؟ ... أو على الأقل، لديها القدرة على احتواء الأشياء الأخرى، من حيث رمز الفئة الخاصة بك. منها مثلا.

public abstract class MudObject
{
    MudObject containedBy;
    List<MudObject> contains;
}

وبعد ذلك يمكنك وضع بعض نوع من العلم على الكائن نفسه لتحديد ما إذا كان لاعبين قادرين على وضع فعلا الأشياء داخل أو خارج الكائن أنفسهم، بدلا من استخدام نوع الكائن لأنها من أصل الرقم.

في الواقع، بل هو فكرة سيئة عن شيء ليكون كل عنصر و حاوية. هذا يكسر عدد من السيناريوهات التي تجعل افتراضات حول IList ملزمة. ذلك لصدره، وأنا قد تميل لخاصية عناصر <م> على الصدر الذي هو جمع، ولكن دعونا الصدر يكون مجرد الصدر.

ولكن، للسؤال عن طلب ...

وأود أن يميل إلى جعل MudObject واجهة ... بهذه الطريقة، يمكنك استخدام شيء من هذا القبيل ما يلي، والتي تعطيك حاوية العامة من أي أشياء ملموسة، جنبا إلى جنب مع تربية الأطفال التلقائي:

public interface IMudObject
{
    IMudObject Container { get; set; }
    /* etc */
}

public class MudContainer<T> : Collection<T>, IMudObject
    where T : IMudObject
{

    public IMudObject Container { get; set; }

    protected override void ClearItems()
    {
        foreach (T item in this)
        {
            RemoveAsContainer(item);
        }
        base.ClearItems();
    }

    protected override void InsertItem(int index, T item)
    {
        SetAsContainer(item);
        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
        RemoveAsContainer(this[index]);
        base.RemoveItem(index);            
    }
    protected override void SetItem(int index, T item)
    {
        RemoveAsContainer(this[index]);
        SetAsContainer(item);
        base.SetItem(index, item);
    }

    void RemoveAsContainer(T item)
    {
        if (item != null && ReferenceEquals(item.Container, this))
        {
            item.Container = null;
        }
    }
    void SetAsContainer(T item)
    {
        if (item.Container != null)
        {
            throw new InvalidOperationException("Already owned!");
        }
        item.Container = this;
    }
}

والذهاب مع فكرة تكوين أكثر من إجابة الميراث الذي يبدو أنه قد اختفت.

وربما أستطيع أن أفعل شيئا أكثر من هذا القبيل

public class Container<T> where T : MudObject
{
    List<T> Contains;
    MudObject containerOwner;

    public Container(MudObject owner)
    {
        containerOwner = owner;
    }
    // Other methods to handle parent association
}

public interface IMudContainer<T> where T : MudObject
{
    Container<T> Contains { get; }
}

public class MudObjectThatContainsStuff : IMudContainer
{
    public MudObjectThatContainsStuff()
    {
        Contains = new Container<MudObject>(this);
    }

    public Contains { get; }
}

وعلى طول خطوط الجواب مارك، وإرسال اثنين من الطبقات التي تحافظ على العلاقة بين الوالدين والطفل ثنائية الاتجاه تحت غطاء محرك السيارة.

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