Frage

Ich schreibe einen MUD-Engine, und ich habe auf dem Spiel-Objektmodell gerade erst begonnen, das erweiterbar sein muss.

Ich brauche in erster Linie helfen, weil das, was ich getan habe, fühlt sich chaotisch, aber ich kann eine andere Lösung nicht denken, das besser funktioniert.

Ich habe eine Klasse namens MudObject, und eine andere Klasse namens Container, kann ein Behälter mehrere MudObjects enthalten, ist aber ein MudObject selbst aber MudObjects müssen wissen, was sie in enthalten sind.

So sie in etwa so aussehen:

public abstract class MudObject
{
    Container containedBy;
}

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

(bitte beachten Sie dies sind nur Beispiele und einige Qualifier und Zugriffsmodifikatoren, Eigenschaften und so verpasst off)

Nun ist diese nur an sich scheint chaotisch, aber etwas anderes auf die Mischung hinzufügen können:

Item ist ein MudObject, die alle visuellen Elemente (wie zB Waffen) aus, aber einige von ihnen müssen als Container zu vererbt werden (wie Kisten). Aber es gibt keinen wie Mehrfachvererbung in C #, so kommt es darauf an Schnittstellen, wäre die beste Wahl sein, den Behälter eine Schnittstelle (soweit ich sehen kann) zu machen, aber es gibt einen Grund war ich es nicht sein wollen, dass ist, dass der Behälter eine MudObject in einen Behälter Zugabe bewirkt, dass der MudObjects .containedBy Wert.

aktualisieren

Irgendwelche Ideen, die diese Arbeit machen würde, oder falle ich in die Falle der Dinge zu kompliziert zu machen?
Wenn ja, was sonst könnte man vorschlagen?

War es hilfreich?

Lösung

Was Sie für Fragen angemessen ist, und ist der Composite Design Pattern

Andere Tipps

Ich glaube, Sie sind overcomplicating. Wenn MudObjects andere MudObjects enthalten kann, die einzige Basisklasse, die Sie benötigen, sollten in dieser Richtung sein:

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

Dies ist ähnlich wie die Art und Weise WinForms und ASP.NET funktioniert. Viele Container-Steuerelemente sind beide Kontrollen und eine Sammlung von subcontrols enthalten kann.

Was Sie wollen, ist durchaus sinnvoll. Es ist nicht anders als Windows-Formular-Steuerelemente, die kann sich ein Container anderer Steuerelemente sein

Was Sie tun müssen, ist eine eigene Implementierung von List<MudObject> zu erstellen:

public class MudObjectList : List<MudObject>

, die unter anderem implementiert, wird die Add-Funktionalität:

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

Hinweis: Diese Methode Schatten, statt Überschreibungen, die alte Add-Funktionalität

Auf diese Weise füllen Sie sofort das ContainedBy Attribut auf Hinzufügen. Natürlich ist es impliziert, dass Ihr ContainedBy null werden kann, was bedeutet, dass es das Top-Level-Objekt ist.

Schließlich, ich glaube nicht, dass es eine Notwendigkeit, separate MudObject und Container Klassen zu machen, da ein Behälter ist mit einem MudObject intrinsischen sehe (die ff verwendet C # 3.0 automatische Eigenschaften):

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

Warum nicht alle MudObjects Container machen? ... oder zumindest die Möglichkeit hat, andere Objekte zu enthalten, in Bezug auf Ihren Klassencode. Z.

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

Sie können dann eine Art Fahne auf dem Objekt gesetzt selbst, ob die Spieler in der Lage sind zu identifizieren, die tatsächlich Dinge zu setzen in der oder aus dem Objekt selbst, anstatt die Art des Objekts mit, es herauszufinden.

Eigentlich ist es eine schlechte Idee für etwas sowohl ein Element und ein Container zu sein. Dies bricht eine Reihe von Szenarien Bindung, die Annahmen über IList machen; so für eine Brust, ich könnte versucht sein, eine Eigenschaft Item haben auf die Brust, dass die Sammlung, aber lassen Sie die Brust nur eine Brust sein.

Doch für die Frage, wie gefragt ...

Ich wäre versucht, die MudObject die Schnittstelle zu machen ... Auf diese Weise können Sie so etwas wie die folgenden verwenden, die Ihnen einen generischen Container von irgendwelchen konkreten Objekten gibt, zusammen mit automatischer Kindererziehung:

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

mit der Idee der Komposition der Vererbung Antwort gehen, die verschwunden zu sein scheint.

Vielleicht wie dies könnte ich etwas mehr tun

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

Nach dem Vorbild von Marc Antwort, schreibt ein paar Klassen, die eine bidirektionale Eltern-Kind-Beziehung unter der Haube halten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top