使用Java 8排队方法

时间:2014-02-28 21:25:29

标签: java java-8

我正在构建一个游戏模拟器,它具有数百个微步骤,如下所示。他们每个人都执行一项独特的任务,但为了简洁起见,我省略了实施细节。

public class Sim {

    static void phase() {
        phaseIn();
        phaseOut();
    }

    static void untap() {
    }

    static void upkeep() {
    }

    static void draw() {
    }

    ...
}

Turn通常涉及按顺序执行步骤,但有时候特殊效果可能会导致序列发生变化。例如,我可能需要重复两次步骤,跳过一步或重新排列步骤的顺序。这些操作都是特殊情况,因为转弯通常只是从开始到结束的顺序发生。

例如,以下一系列事件代表我的正常转向。

...> upkeep() > draw() > preCombatMain() > ......

现在,我发挥了一些需要我重复绘制步骤的东西。我需要轮到我这样:

...> upkeep() > draw() > draw() > preCombatMain() > ...

转弯的步骤是方法,我不知道如何将方法排队或出列。我知道Java 8有方法引用,但该功能相对较新。我无法将existing tutorials应用于我想要完成的任务。我到Sim::untap,但我不知道如何分配,调用它等。如何在Java 8中排队方法,或以其他方式调用方法确定在运行时由玩家做出的选择?

注意:我意识到我无法理解可能是由于一个基本的设计缺陷。我从未参加过游戏设计课程,我完全接受批评,如果有缺陷,我会改变我的设计。也就是说,问题不应该被误解为“请推荐一种设计模式”。我考虑了一个替代设计,我在一个庞大的switch语句中“编号”每一步,排队“数字”,并反复切换队列的前面,但这看起来像一个糟糕的计划(在我看来)。

2 个答案:

答案 0 :(得分:4)

如果您只是希望它们按顺序运行,您当然可以一个接一个地调用它们。如果订单可以更改,则另一种方法是使用方法引用队列:

LinkedList<Runnable> queue = new LinkedList<>();
queue.add(Sim::upkeep);
queue.add(Sim::draw);
queue.add(Sim::preCombatMain);
queue.forEach(Runnable::run);

我能够使用LinkedList<Runnable>,因为您的方法的签名是void m()。对于其他签名,您可以使用其他类型,例如:

  • void m()使用Runnable
  • T m()使用Supplier<T>
  • void m(T o)使用Consumer<T>
  • R m(T o)使用Function<T, R>

答案 1 :(得分:2)

解决方案是使用多态。定义步骤的界面:

interface Step {
  void process();
}

然后通过实施来定义每个步骤:

class UpkeepStep implements Step {
  void process() { ... }
}

现在你可以把你所有的步骤放在一个数组中,如果需要的话,将它洗牌,并执行所有步骤,如下所示:

for (Step step : steps) {
  step.process();
}

可能运行得更快的另一种方法是生成包含方法调用的代码,编译它并加载类。但是,如果与方法调用开销相比,步骤没有花费太多运行时间,并且如果您经常执行每个生成的代码,那么它只会提供更好的性能,因此JIT将对其进行优化。