我正在编写一个MUD引擎,我刚开始使用游戏对象模型,它需要是可扩展的。
我需要帮助主要是因为我所做的事情感觉很乱,但我想不出另一个更好的解决方案。
我有一个名为MudObject
的类,另一个名为Container
的类,一个容器可以包含多个MudObjects
,但是MudObject
本身,{{1}需要知道它们包含在哪里。
所以他们看起来像这样:
MudObject
(请注意这些只是示例,一些限定符和访问修饰符,属性等都被遗漏了)
现在这个本身看起来很混乱,但是我们可以在其中添加其他内容:
public abstract class MudObject
{
Container containedBy;
}
public abstract class Container : MudObject
{
List<MudObject> Contains;
}
是一个Item
,所有可视物品(如武器)都将继承,但其中一些也需要是容器(如箱子)。但是在c#中没有多重继承,所以它归结为接口,最好的选择是使容器成为一个接口(据我所知)但是有一个原因我不想要它,因为向容器添加MudObject
会导致容器更新MudObject
的{{1}}值。
任何会使这项工作成功的想法,或者我是否陷入过于复杂化的陷阱? 如果是这样,你还能提出什么建议?
答案 0 :(得分:4)
我认为你过于复杂。如果MudObjects可以包含其他MudObjects,那么您需要的单个基类应该是这些行:
public abstract class MudObject
{
MudObject containedBy; //technically Parent
List<MudObject> Contains; //children
}
这类似于WinForms和ASP.NET的工作方式。许多容器控件都是控件,并且可以包含一组子控件。
答案 1 :(得分:1)
你想要的是非常合理的:它与Windows窗体控件没什么不同,它本身就是其他控件的容器。
您需要做的是创建自己的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; }
}
答案 2 :(得分:1)
您所要求的是合理的,并且是Composite Design Pattern
答案 3 :(得分:0)
为什么不制作所有MudObjects容器? ...或者至少,能够根据类代码包含其他对象。 E.g。
public abstract class MudObject
{
MudObject containedBy;
List<MudObject> contains;
}
然后,您可以在对象本身上设置某种标记,以识别玩家是否能够实际将东西放入或移出对象本身,而不是使用对象的类型来计算出来。
答案 4 :(得分:0)
实际上,将某个项目和都设置为容器是一个坏主意。这打破了许多对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;
}
}
答案 5 :(得分:0)
与继承答案相似的构思想法似乎已经消失了。
也许我可以做更像这样的事情
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; }
}
答案 6 :(得分:0)
按照Marc的回答,写下几个维持双向亲子关系的课程。