5

私は3つの異なるリンクリストのクラスを持っています(私が取り組んでいるゲームでエンティティを保存するため)。リストはすべて同じ基本タイプのオブジェクトですが、処理上の理由から別々にしています。IEntity、IObject、および IUndead はすべて IEntity から継承されていることに注意してください。

public class EntityBucket
{
    public LinkedList<IEntity> undeadEntities;
    public LinkedList<IEntity> objects;
    public LinkedList<IEntity> livingEntities;

    public EntityBucket()
    {
        undeadEntities = new LinkedList<IEntity>();
        objects = new LinkedList<IEntity>();
        livingEntities = new LinkedList<IEntity>();
    }

    public LinkedList<IEntity> GetList(IObject e)
    {
        return objects;
    }

    public LinkedList<IEntity> GetList(IUndead e)
    {
        return undeadEntities;
    }

    public LinkedList<IEntity> GetList(ILiving e)
    {
        return livingEntities;
    }

}

現在、パラメーターに基づいて、各リストを取得するための 3 つの方法があります。各リストには何らかの方法で独自のアクセサーが必要になることがわかっているため、3 つあるという事実は問題ありません。ただし、インスタンス化されたオブジェクトを渡すのは理想的ではありません。同様のタイプのオブジェクトが手元になくても、どこかでリストを取得したい場合があるからです。ここのオブジェクトは GetList メソッドでも使用されないことに注意してください。使用するバージョンを決定するためだけに存在します。インスタンス化されたオブジェクトが手元にある例を次に示します。

public void Delete(IUndead e, World world)
{

     .....
     LinkedList<IEntity> list = buckets[k].GetList(e);
     .....
}

インスタンス化されたオブジェクトが手元にあるとは限らないため (たとえば、エンティティをレンダリングするとき)、この現在の実装は好きではありません。私はそれを一般的に行うことを考えていましたが、私がやりたいことでこれが可能かどうかはわかりません。これに伴い、3 つの Delete メソッド (および add などのその他の 3 つのメソッド) も必要です。IUndead、IObject、および ILiving の各タイプに 1 つです。これは正しいやり方ではないと感じています。

リクエストがあれば、これまでに試したことを投稿しますが、私のジェネリックはかなり悪いので、これを読むのはもったいないと感じています。

最後に、パフォーマンスは非常に重要です。私は時期尚早に最適化しているのではなく、既にコードが動作しているので最適化後に行っていますが、高速化する必要があります。getlist メソッドは非常に頻繁に呼び出されるため、明示的な型チェックは避けたいと考えています。

4

4 に答える 4

3

あなたが言ったように、GetListそのタイプを理解するためだけに不要なオブジェクトを渡すことはほとんど意味がないので、より良いインターフェースが必要です。

次のようなことができます:

public List<IEntity> GetList<T>() : where T:IEntity
{
    if(typeof(T)==typeof(IUndead)) return undedEntities;
    // and so on
}

そして、次のように呼び出す必要があります。GetList<IUndead>();

ここでは列挙型の方が良い考えだと思います:

enum EntityTypes { Undead, Alive, Object };
public List<IEntity> GetList(EntityTypes entityType) { ... }

それはよりクリーンで、私にとってより理にかなっています。

編集:ジェネリックの使用は、実際にはそれほど単純ではありません。誰かがZombieIUndead を実装する GetList を型と呼ぶことができた場合、インターフェイスの実装を確認する必要があります。誰かがLiveZombieIUndead と IAlive の両方を実装する を渡すことさえできます。間違いなく列挙型を使用してください。

于 2012-05-16T20:12:51.240 に答える
1

そのより良いインターフェースに合うより良い実装はどうですか?

public class EntityBucket
{
  public LinkedList<IEntity> Entities;

  public IEnumerable<T> GetEntities<T>() where T : IEntity
  {
    return Entities.OfType<T>();
  }

}


List<IUndead> myBrainFinders = bucket.GetEntities<IUndead>().ToList();

この実装では、呼び出し元は各アイテムを適切なリストに追加する方が適切です。これは元の実装の要件だったので、問題ないと思います。

public class EntityBucket
{
  Dictionary<Type, List<IEntity>> entities = new Dictionary<Type, List<IEntity>>();

  public void Add<T>(T item) where T : IEntity
  {
    Type tType = typeof(T);
    if (!entities.ContainsKey(tType))
    {
      entities.Add(tType, new List<IEntity>());
    }
    entities[tType].Add(item);
  }

  public List<T> GetList<T>() where T : IEntity
  {
    Type tType = typeof(T);
    if (!entities.ContainsKey(tType))
    {
      return new List<T>();
    }
    return entities[tType].Cast<T>().ToList();
  }

  public List<IEntity> GetAll()
  {
    return entities.SelectMany(kvp => kvp.Value)
      .Distinct() //to remove items added multiple times, or to multiple lists
      .ToList();
  }

}
于 2012-05-17T17:53:12.470 に答える
1

以下のようなものはいかがでしょうか?

public LinkedList<IEntity> GetList(Type type) {
    if (typeof(IUndead).IsAssignableFrom(type)) return undeadEntities;
    if (typeof(ILiving).IsAssignableFrom(type)) return livingEntities;
    if (typeof(IObject).IsAssignableFrom(type)) return objects;
}

次に、次のように呼び出します。

var myUndeads = GetList(typeof(IUndead));
var myLivings = GetList(typeof(ILiving));
// etc

同じタイプのロジックを削除、追加、およびその他のメソッドに実装でき、それらにアクセスするためにオブジェクトの具体的なインスタンスは必要ありません。

ロジックは、IsAssignableFromサブクラス化を適切に処理します (つまりCatZombie、 から派生しZombie、 を実装するがあっIUndeadても、これは引き続き機能します)。つまり、次のような Delete メソッドを 1 つ作成するだけで済みます。

public void Delete(IEntity e, World world) {
    if (typeof(IUndead).IsAssignableFrom(type)) undeadEntities.Remove(e);
    if (typeof(ILiving).IsAssignableFrom(type)) livingEntities.Remove(e);
    if (typeof(IObject).IsAssignableFrom(type)) objects.Remove(e);
}

編集:パフォーマンスに関する zmbq の回答に対するあなたのコメントに気付きました。これは間違いなく高速ではありません。高いパフォーマンスが必要な場合は、列挙型のアプローチを使用してください。コードはより冗長になり、より多くのメンテナンスが必要になりますが、パフォーマンスは大幅に向上します。

于 2012-05-16T20:23:24.300 に答える
0

名前付きの LinkedList の Dictionary を実装して、名前または列挙型で参照することができるように思えます。

そうすれば、リストの追加または削除は単なる実装の問題であり、個別のクラスを処理する必要はありません。

于 2012-05-17T17:43:12.650 に答える