2008-10-22 4 views
2

J'écris un moteur MUD et je viens juste de commencer sur le modèle objet de jeu, qui doit être extensible.Conseils avec Hiérarchie des classes des articles de jeu

je besoin d'aide principalement parce que je l'ai fait se sent en désordre, mais je ne peux pas penser à une autre solution qui fonctionne mieux.

J'ai une classe appelée MudObject, et une autre classe appelée Container, un conteneur peut contenir plusieurs MudObjects, mais est un MudObject lui-même, cependant MudObject s doivent savoir ce qu'ils sont contenus dans.

Alors ils regardent quelque chose comme ceci:

public abstract class MudObject 
{ 
    Container containedBy; 
} 

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

(s'il vous plaît noter que ce sont par exemple juste et des qualificatifs et des modificateurs d'accès, les propriétés et telles sont manquées au large)

Maintenant tout cela en soi semble désordonné, mais permet d'ajouter quelque chose d'autre au mélange:

Item est un MudObject que tous les éléments visuels (comme les armes) seront héritées de, mais certains d'entre eux ont besoin d'être conteneurs aussi (comme des coffres). Mais theres pas comme l'héritage multiple dans C#, Donc, il revient à des interfaces, le meilleur choix serait de faire du conteneur une interface (pour autant que je puisse voir) Cependant, il y avait une raison pour laquelle je ne voulais pas être, à savoir que l'ajout d'un MudObject à un récipient provoque le récipient pour mettre à jour la valeur de MudObject.containedBy.

Toutes les idées qui rendraient ce travail, ou suis-je tomber dans le piège de faire des choses trop compliquées?
Si oui, que pourriez-vous suggérer d'autre?

+0

Notez mon point sur les liaisons; plutôt que d'avoir le coffre * être * un conteneur, pensez à laisser le coffre avoir une propriété (comme des objets) qui est le conteneur ... –

+0

Voir ma propre réponse :) – Sekhat

Répondre

1

Ce que vous voulez est tout à fait raisonnable: il est pas différent de contrôles de formulaire Windows, qui peut lui-même être un conteneur d'autres contrôles.

Ce que vous devez faire est de créer votre propre implémentation de List<MudObject>:

public class MudObjectList : List<MudObject> 

qui met en œuvre, entre autres, la fonctionnalité ajouter:

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

Note: cette ombre méthode, au lieu de les modifier, l'ancien ainsi Ajouter fonctionnalité

vous remplissez immédiatement le C Attribut ontainedBy lors de l'ajout. Bien sûr, il est implicite que votre ContainedBy peut être null, ce qui signifie qu'il s'agit de l'objet de niveau supérieur.

Enfin, je ne pense pas qu'il y ait un besoin de faire MudObject et Container séparées des classes, car étant un conteneur semble intrinsèque à un MudObject (ff utilise C# 3.0 propriétés automatiques):

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

La liste n'expose pas un ajout virtuel que vous pouvez outrepasser –

0

Pourquoi ne pas faire tous les conteneurs MudObjects? ... ou au moins, avoir la capacité de contenir d'autres objets, en termes de votre code de classe. Par exemple.

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

Vous pouvez ensuite définir une sorte de drapeau sur l'objet lui-même afin de déterminer si les joueurs sont capables de mettre réellement les choses dans ou hors de l'objet eux-mêmes, plutôt que d'utiliser le type de l'objet pour le comprendre .

0

En fait, c'est une mauvaise idée que quelque chose soit à la fois un article et un conteneur. Cela casse un certain nombre de scénarios contraignants qui font des hypothèses sur IList; Donc, pour un coffre, je pourrais être tenté d'avoir une propriété Articles sur la poitrine qui est la collection, mais laissez la poitrine juste être un coffre.

Cependant, la question a demandé ...

Je serais tenté de faire le MudObject l'interface ... De cette façon, vous pouvez utiliser quelque chose comme ce qui suit, ce qui vous donne un conteneur générique de tout objets concrets, ainsi que la parentalité automatique:

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

Je pense que vous êtes trop compliqué. Si MudObjects peut contenir d'autres MudObjects, la classe de base unique dont vous avez besoin doit être le long de ces lignes:

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

Ceci est similaire aux winforms et fonctionne ASP.NET façon. De nombreux contrôles de conteneur sont à la fois des contrôles et peuvent contenir une collection de sous-contrôles.

+0

Mais tous les objets MudObjects ne peuvent pas contenir d'autres objets MudObjects – Sekhat

+0

Cette conception rend la maintenance difficile, car vous devez gérer manuellement les relations parent et enfant. –

+0

@Killersponge, si tel est le cas, vous pouvez définir l'accès à la liste Contient comme une propriété et ajouter une propriété permettant à un objet d'avoir des sous-objets. –

0

Aller avec l'idée de la composition sur l'héritage réponse qui semble avoir disparu.

Peut-être que je pouvais faire quelque chose comme ce

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

Le long des lignes de la réponse de Marc, écrire deux classes qui entretiennent une relation parent-enfant bidirectionnel sous le capot.

Questions connexes