如何处理大量的if-else语句?

时间:2011-05-08 22:06:36

标签: java

我正在为项目创建游戏模拟器。游戏由两支军队相互战斗组成。每支军队由多名士兵组成。士兵正在执行指令(从文本中读取)。

每条指令都是一个像移动,转动等命令。我来到了需要创建一个方法的部分,该方法将检查下一条指令是什么并执行它。指令不太相似,这意味着它们没有相同的方法。

运行此方法的类存储游戏字段(2d数组)和所有士兵的数组,循环遍历它并执行每个士兵拥有的下一条指令。所以在这一点上,我有一个很长的列表,if-else描述每条指令会发生什么。我正试图找到一种更好的方法来写这个,但无法弄清楚如何。我知道很少有设计模式但我无法通过接口或继承来实现这一点(不确定它是否可行)。

如何解决if-else语句和长代码太多的问题?

我知道这里可能没有足够的信息,但任何建议都表示赞赏。

4 个答案:

答案 0 :(得分:2)

  

指令不太相似,这意味着它们没有相同的方法[...]如何解决if-else语句和长代码太多的问题?

一般情况下,如果你有“如果这种类型,那么这样做”,那么你就有了多态性(虚函数)的情况。在这种情况下,每个实体的共同点是,您正在尝试更新游戏模拟,游戏的每个部分(每个士兵)对更新模拟的含义都有不同的概念。

  

我已经到了需要创建一个方法的部分,该方法将检查下一条指令是什么并执行它。

我建议将其拆分为多个抽象级别:

  • 模拟本身的表示
  • 从用户那里获取输入(阅读文件)
  • 将输入转换为模拟中的操作

您希望获得此类独立性的原因是,如果您决定更改接受模拟输入的方式,则无需重新构建整个游戏。

游戏模拟

每个游戏都必须设置某种初始状态,因此他们知道世界应该是什么样子,以及每个动作应该如何改变这个世界。

在该状态设置之后,模拟将遍历一个全局循环,通常称为“游戏循环”,并将继续循环直到模拟完成(您退出,游戏结束,或者没有更多输入)。

大多数游戏如何处理他们的输入:

在每个游戏循环开始时,他们会查找自上次循环以来的用户输入。他们可能会寻找按键,鼠标输入,控制台上的输入,网络数据包等。他们接受此输入并将其转换为动作以进行模拟处理。

大多数游戏如何处理模拟:

大多数游戏为每个游戏实体制作一个抽象基类,并保留所有实体的全局集合。实体基类将提供虚拟Update方法。此方法将采用执行更新所需的任何状态。

一个例子,使用C#语法(抱歉,我不懂Java)

public abstract class GameEntity
{
    public abstract void Update(TimeSpan timeElapsedSinceLastUpdate, World theWorld);
}

通过游戏循环的每次迭代,游戏将在所有实体中进行子循环,在每个实体上调用Update。每个游戏实体都有自己的Update实现。

特定实体可能会对输入做出反应,或更新某些内部状态。它可能会根据其速度更新其位置。它可能会检查自上次更新以来用户引发的操作,以查看是否应更改其加速度/位置。它可以检查是否已经过了足够的时间来在游戏状态之间转换(例如,从counting-down状态到exploding状态。它可能会与世界上其他实体进行交叉/碰撞测试。

关键在于时间向前推进,每个游戏实体都可以拥有自己独立的概念,即时间变化。

如果您的游戏是基于回合的(因此不需要时钟时间的概念),或者每个实体已经有对世界的引用,您可以从基础Update方法的签名中删除它们。如果此参数有用,您也可以考虑添加int updateNumberint currentTurn参数。

如何处理模拟:

您可能将士兵作为唯一的实体类型。动作将独立于更新命令传递给士兵。然后,在调用更新时将执行操作。

如何处理模拟的初始状态:

你必须弄清楚你必须从多少士兵开始,以及他们的属性(类型,等级,健康等)。您可能还需要有关世界的信息,例如网格大小或可能的地形数据。

如何处理输入:

  • 您可以在创建士兵时提供操作,跟踪操作以及应该执行哪个操作
  • 您可以在每次转弯/更新前将要执行的操作提供给每个实体

无论哪种方式取决于您,但在每次更新之前进行操作都会让您的游戏在未来更灵活地进行更改。在大多数互动游戏中,用户倾向于一次输入一个回合。

这也不会限制您在每回合创建要执行的命令队列,因为实体本身不必处理队列,因此它不必知道存在这样的队列。

答案 1 :(得分:1)

您可能希望查看State Pattern

答案 2 :(得分:1)

如果您考虑一下,您真正​​想要做的是创建一种专门针对您的游戏的新语言。它被称为DSL(域特定语言)。

这在计算机科学中非常普遍。

如果您认为您的语言会非常简单,那就是:

command1 arg1 ... argn
..
commandN argN1 ... argNn

然后,您可以使用pattern命令并按名称查找正确的命令。这就是其他回应。

但这确实是BASIC。你如何管理错误?太多,没有足够的论据?最终条件表达式或循环?如何向您的命令发送复杂的结构或参数?如何定义'宏'或命令列表?

如果你想要更多的东西取决于你真正想做的事情,你可以选择几条路线:

  • 将XML格式与XSD一起使用 而不是自由文本将允许 验证时间检查您的清单 订单及其参数它 也允许使用或出现 数据结构,宏观或简单 表达。更好,但不是那么容易 在眼睛上阅读。
  • 使用现有的脚本语言 (比如Groovy,Jython,clojure ......) 那可以很好地嵌入java中,所以 您的命令实际上是源代码 码。所以他们可以做任何事情 语言许可(所以你有循环, 功能,任何脚本 语言可以做),你暴露了 允许控制你的API 其中的士兵。
  • 你真的想要特定的东西。一个 特殊语言,可能更多 比我的例子中的那个更高, 但不想包含常规 脚本语言。你有一个范围 来自Eclipse的XText等工具集 设计的建模框架 只是为了那个。帮助制作DSL。 或者您可以定义语法和使用 像ANTR这样的解析器可以帮助你。

这是一个非常广泛的主题,如果您的需求是基本的,大的开关案例,或命令模式就足够了。如果你想要更专业但仍然有效的东西,我会尝试我指出的其他解决方案之一并花时间看看每个人能提供什么,可能与否,以及它如何为你服务......或者不是。

答案 3 :(得分:0)

当然有可能:)你会使用polymorphismHere's an excellent example