我正在编写一个MUD引擎,我刚开始使用游戏对象模型,它需要是可扩展的。

我需要帮助主要是因为我所做的事情感觉很乱,但我想不出另一个更好的解决方案。

我有一个名为MudObject的类,另一个名为Container的类,一个容器可以包含多个MudObjects,但是Item本身,但.containedBy需要知道它们包含在哪个中

所以他们看起来像这样:

public abstract class MudObject
{
    Container containedBy;
}

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

(请注意这些只是示例,一些限定符和访问修饰符,属性等都被遗漏了)

现在这个本身看起来很混乱,但是我们可以在其中添加其他内容:

<=>是<=>所有可视物品(如武器)都将继承,但其中一些也需要是容器(如箱子)。但是在c#中没有多重继承,所以它归结为接口,最好的选择是使容器成为一个接口(据我所知)但是有一个原因我不想要它,因为向容器添加<=>将导致容器更新<=> s <=>值。

任何可以使这项工作成功的想法,或者我是否陷入过于复杂化的陷阱?
如果是这样,你还能提出什么建议?

有帮助吗?

解决方案

您所要求的是合理的,并且是复合设计模式

其他提示

我认为你过于复杂。如果MudObjects可以包含其他MudObjects,那么您需要的单个基类应该是这些行:

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

这类似于WinForms和ASP.NET的工作方式。许多容器控件都是控件,并且可以包含一组子控件。

你想要的是非常合理的:它与Windows窗体控件没什么不同,它本身就是其他控件的容器。

您需要做的是创建自己的List<MudObject>

实现
public class MudObjectList : List<MudObject>

除其他外,还实现了添加功能:

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

注意:此方法隐藏旧的添加功能

而不是覆盖

这样,您可以在添加时立即填充ContainedBy属性。当然暗示您的ContainedBy可以是null,这意味着它是顶级对象。

最后,我认为不需要单独的MudObjectContainer类,因为它是一个容器,看起来是<=>固有的(ff使用C#3.0自动属性):

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

为什么不制作所有MudObjects容器? ...或者至少,能够根据类代码包含其他对象。 E.g。

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

按照Marc的回答,写下几个维持双向亲子关系的课程。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top