Pergunta

Eu estou escrevendo um motor de lama e I acabou de começar no modelo de objeto do jogo, que precisa ser extensível.

Preciso de ajuda, principalmente porque o que eu fiz sente confuso, mas eu não posso pensar de uma outra solução que funciona melhor.

Eu tenho uma classe chamada MudObject, e outra classe chamada Container, Um recipiente pode conter múltiplas MudObjects, mas é um MudObject si, no entanto MudObjects precisa saber o que eles estão contidos.

Assim que algo parecido com isto:

public abstract class MudObject
{
    Container containedBy;
}

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

(por favor, note que estes são apenas exemplo e alguns qualificadores e modificadores de acesso, propriedades e tais são perdidas off)

Agora é só isso por si só parece confuso, mas vamos acrescentar algo mais à mistura:

Item é um MudObject que todos os itens visuais (como armas) será herdada de, entretanto, algumas destas necessidade de ser recipientes também (como caixas). Mas não há nenhuma como a herança múltipla em c #, por isso se resume às interfaces, a melhor opção seria fazer o recipiente de uma interface (tanto quanto eu posso ver) No entanto, houve uma razão que eu não quero que ele seja, que é que a adição de um MudObject para um recipiente fará com que o recipiente para atualizar o valor MudObjects .containedBy.

Todas as idéias que fariam este trabalho, ou estou cair na armadilha de fazer as coisas muito complicadas?
Se assim o que mais você poderia sugerir?

Foi útil?

Solução

O que você está pedindo é razoável, e é o padrão Composite Design

Outras dicas

Eu acho que você está complicar. Se MudObjects pode conter outros MudObjects, a classe base única que você precisa deve ser ao longo destas linhas:

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

Esta é semelhante à forma como WinForms e obras ASP.NET. Muitos controles de recipiente são ambos os controles, e pode conter uma coleção de subcontrols.

O que você quer é bastante razoável:. Não é diferente de controles de formulários do Windows, o que em si pode ser um recipiente de outros controles

O que você precisa fazer é criar sua própria implementação de List<MudObject>:

public class MudObjectList : List<MudObject>

que implementa, entre outras coisas, a funcionalidade add:

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

Nota: Este método sombras, em vez de substituições, o antigo adicionar funcionalidade

Desta forma você preencher imediatamente o atributo ContainedBy mediante adição. Claro que está implícito que o seu ContainedBy pode ser null, o que significa que é o objeto de nível superior.

Finalmente, eu não acho que há uma necessidade de fazer aulas MudObject e Container separadas, desde que seja um recipiente parece intrínseca a um MudObject (o ff usa C # 3.0 propriedades automáticas):

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

Por que não fazer todos os MudObjects recipientes? ... ou, pelo menos, ter a capacidade de conter outros objetos, em termos de seu código de classe. Por exemplo.

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

Você pode então definir algum tipo de bandeira no próprio objeto para identificar se os jogadores são capazes de coisas realmente colocar para dentro ou fora do objeto a si mesmos, ao invés de usar o tipo de objeto para descobrir isso.

Na verdade, é uma má idéia para algo ser tanto um item e um recipiente. Isso quebra uma série de cenários que fazem suposições sobre IList vinculativa; assim para um baú, eu poderia ser tentado a ter uma propriedade Items em do peito que é a coleção, mas deixar o peito ser apenas um peito.

No entanto, para a pergunta como pediu ...

Eu seria tentado a fazer a MudObject a interface ... dessa forma, você pode usar algo como o seguinte, o que lhe dá um contêiner genérico de quaisquer objetos concretos, juntamente com a parentalidade automática:

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

Indo com a idéia de composição ao longo resposta herança que parece ter desaparecido.

Talvez eu pudesse fazer algo mais como este

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

Ao longo das linhas de resposta de Marc, escrever um par de classes que mantêm uma relação pai-filho bidirecional sob o capô.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top