我正在构建一个游戏模拟器,它具有数百个微步骤,如下所示。他们每个人都执行一项独特的任务,但为了简洁起见,我省略了实施细节。
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语句中“编号”每一步,排队“数字”,并反复切换队列的前面,但这看起来像一个糟糕的计划(在我看来)。
答案 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将对其进行优化。