你如何设计概念上具有绝大多数“类型”或子类的类?

时间:2012-07-14 08:13:53

标签: oop design-patterns

详细说明我的问题,具体情况如下:

如果我有一个模拟或游戏项目,例如,Monster类具有不同的统计数据作为成员数据(hitPointsRemainingAttackDamage等),我想拥有任何具有常数基数统计数据的不同类型的怪物数量(MaxHPSpeed等),然后我看到了这个类需要使用的三种方式:

  1. 一个实际的类,其中包含用于在整个代码中使用Monster对象的接口(例如,“Monster”)
  2. 不同类型怪物的实际“数据”。 (概念上可能的子类?虽然我确定这不是正确的解决方案)例子:地精,龙,独眼巨人等
  3. 实际实例化Monster个对象,代表不同的怪物,因为角色在游戏中遇到它们(可能随时有多个相同类型的实例)
  4. 我想知道大多数设计师是如何实现这一目标的。 我的想法如下:

    - 制作一个Monster类然后为每个类型的怪物创建一个新的子类是没有意义的。这似乎是一个非常混乱和不可维护的解决方案,特别是如果不同的怪物类型的数量变化数百,并且每种类型之间的差异不足以保证新的子类

    -Rather,我的解决方案如下: 1.拥有一个文件,可以添加到包含表中所有不同Monster类型及其特征的数据。该表可以在项目开发的任何时候添加。

    1. 编写一个函数,将表中的数据加载到Monster对象中。

    2. 在程序开头写一个初始化调用,可能在某种MonsterManager类中,解析文件并创建一个实例化Monster对象的静态或成员向量从文件中的表格填写的“基础”统计数据(即起始点等)

    3. 每当我想要实例化某种类型的新Monster以添加到某人的军队或让某人遇到某人时,请从该向量中选择Monster(随机或通过一些确定的因素) )创建一个新的Monster对象,并将其从向量中复制出来

    4. 这是一种解决方案还是我出去吃午饭?如果这不是一个好的解决方案,那么有哪些更好的方法?

      其他补充问题:

      - 为向量中保存的怪物数据创建不同的类是否有意义?我以为我可以有一个名为MonsterData的类,它将被上面的MonsterManager构建到一个向量中。我可以将MonsterData对象传递给Monster类的构造函数来实际创建Monster个对象,因为很多Monster个对象的特征将由他们的怪物决定-types(MaxHP,速度等)和其他东西会有所不同(CurrentHP,任何随机变量等)

      - 我认为这个方法是可以优化的,因为你可以做一些事情,比如在表格中添加一个条目,指出怪物出现在哪个级别,然后让MonsterManager初始化函数只加载某些级别的所有怪物立刻缩小内存占用量) - 既然我没有使用enum,那么存储文本字符串是否有意义来识别Monster对象的“类型”?也许从Monster的向量中复制它的MonsterData(或MonsterManager)的指针会更好吗?

      我使用游戏比喻,因为这是我在这里最有意义的,但我想知道在任何情况下这种事情的最佳设计模式。

      谢谢大家!

2 个答案:

答案 0 :(得分:4)

继承应该用于修改/添加行为,而不是用于变化的数据值。在您的示例中,似乎每个怪物都由一组属性(HP,攻击等)定义,并且您希望在游戏中实例化不同的怪物类型。你真的不需要继承。

您与MonsterData班级走在正确的轨道上;这是我将如何去做(大多数只是我认为更有意义的类的不同名称):

// This is what you called MonsterData
// It describes how to create a monster of a specific type
public class MonsterDescription {
  private String type;   // eg. "Goblin"
  private int maxHitPoints;
  private int speed;
  ...
}

// This is an "active" instance of a monster
public class Monster {
  private int currentHitPoints;
  ...

  // static factory method
  public static Monster create(MonsterDescription desc) {
    ...
  }
}

// This is kind of what you called MonsterManager
// Contains a collection of MonsterDescription, loaded from somewhere
public class MonsterDescriptionRepository {
  // finds the description for a given type of monster
  public MonsterDescription find(String type) {
    ...
  }
}

接下来是你如何实例化一个新怪物:

MonsterDescription desc = repository.find("Goblin");
Monster monster = Monster.create(desc);

答案 1 :(得分:2)

dataloader方法似乎适合您的问题 - 它使其易于扩展。 我建议创建不同功能的子类 - 例如,创建一个FlyingMonster子类,它将处理Dragon而不是Goblin或Shark 通过这种方式,您可以(尝试)避免使用可以飞行/跑/潜水的单个怪物类;)

你的最后一个问题是关于外部数据键控 - 为此我认为指针方法是最好的:

  • 这是独一无二的
  • 它可以帮助调试
  • 您可以选择使用商店中存储的值
  • 它将显示与祖先的“is_a”连接

注意:我不认为你应该“关心”任何性能问题(将它们加载到内存中以减少内存占用),因为它通常会破坏设计