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 方法(以及 3 个任何其他方法,例如 add 等) - 每种类型一个,IUndead、IObject 和 ILiving。我只是觉得这不是正确的做法。

我会根据要求发布到目前为止我尝试做的事情,但是我的泛型相当糟糕,我觉得任何人阅读这篇文章也是一种浪费。

最后,性能非常重要。我不是过早地优化,我是后期优化,因为我已经有工作代码,但需要它更快。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) { ... }

它更干净,对我来说更有意义。

编辑:使用泛型实际上并不是那么简单。有人可以将 GetList 称为Zombie实现 IUndead 的类型,然后您必须检查接口实现。有人甚至可以给你一个LiveZombie实现 IUndead 和 IAlive 的。绝对要使用枚举。

于 2012-05-16T20:12:51.240 回答
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 方法,如下所示:

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 回答
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 回答
0

在我看来,您可以只实现一个名为 LinkedList 的字典并通过名称或枚举来引用它们。

这样添加或删除列表只是一个实现问题,不需要处理单独的类。

于 2012-05-17T17:43:12.650 回答