2

私は MUD エンジンを作成しており、拡張可能である必要があるゲーム オブジェクト モデルを開始したばかりです。

主に私がやったことは面倒だと感じているので助けが必要ですが、よりうまく機能する別の解決策が思いつきません.

というクラスと というMudObject別のクラスContainerがあります。コンテナには複数の を含めることができますMudObjectsが、MudObjectそれ自体ですが、MudObjectコンテナが何に含まれているかを知る必要があります。

したがって、それらは次のようになります。

public abstract class MudObject
{
    Container containedBy;
}

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

(これらは単なる例であり、一部の修飾子とアクセス修飾子、プロパティなどが見落とされていることに注意してください)

これだけでも面倒に思えますが、何か他のものをミックスに追加しましょう。

Itemは、MudObjectすべてのビジュアル アイテム (武器など) が継承されるものですが、これらの一部はコンテナ (チェストなど) である必要もあります。しかし、C#には多重継承などはありません。したがって、インターフェースに行き着きます。最良の選択は、コンテナーをインターフェースにすることです(私が見る限り)しかし、そうしたくない理由がありました。つまり、コンテナに を追加するMudObjectと、コンテナがMudObjects.containedBy値を更新します。

これを機能させるアイデアはありますか、それとも物事を複雑にしすぎるという罠に陥っていますか?
もしそうなら、他に何を提案できますか?

4

7 に答える 7

4

あなたは複雑化しすぎていると思います。MudObjects に他の MudObjects を含めることができる場合、必要な単一の基本クラスは次のようになります。

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

これは、WinForms と ASP.NET の動作に似ています。多くのコンテナー コントロールは両方ともコントロールであり、サブコントロールのコレクションを含めることができます。

于 2008-10-22T10:17:08.357 に答える
1

あなたが求めているのは合理的であり、複合デザインパターンです

于 2008-10-22T19:39:00.250 に答える
1

あなたが望むことは非常に合理的です。これは、それ自体が他のコントロールのコンテナーになることができる Windows フォーム コントロールと何ら変わりはありません。

あなたがする必要があるのは、独自の実装を作成することですList<MudObject>:

public class MudObjectList : List<MudObject>

とりわけ、追加機能を実装します。

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

注: このメソッドは、オーバーライドではなく、古い Add 機能をシャドウします。

このようにして、追加時にすぐに ContainedBy 属性を設定します。もちろん、ContainedBy が である可能性があることは暗示されていますnull。これは、それがトップ レベルのオブジェクトであることを意味します。

最後に、コンテナーであることは a に固有のように見えるため(ff は C# 3.0 の自動プロパティを使用します) 、別のMudObjectandクラスを作成する必要はないと思います。ContainerMudObject

public abstract class MudObject
{
    MudObject ContainedBy { get; set; }
    MudObjectList Contains { get; set; }
}
于 2008-10-22T10:14:19.673 に答える
0

マークの答えに沿って、内部で双方向の親子関係を維持するクラスをいくつか作成します。

于 2008-10-22T11:05:54.483 に答える
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; }
}
于 2008-10-22T10:37:43.463 に答える
0

すべての MudObjects コンテナを作成しないのはなぜですか? ...または少なくとも、クラスコードに関して、他のオブジェクトを含めることができます。例えば

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

次に、オブジェクト自体に何らかのフラグを設定して、オブジェクトのタイプを使用して把握するのではなく、プレイヤーが実際にオブジェクト自体に物を入れたり出したりできるかどうかを識別することができます。

于 2008-10-22T10:15:17.643 に答える
0

実際、何かがアイテムとコンテナの両方であることは悪い考えです。これにより、IList に関する仮定を行う多くのバインディング シナリオが破られます。そのため、チェストの場合、コレクションであるチェストに Items プロパティを設定したくなるかもしれませんが、チェストは単なるチェストにします。

しかし、尋ねられた質問に対して...

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;
    }
}
于 2008-10-22T10:15:24.897 に答える