繁体   English   中英

是否可以在循环中的每个方法之后检查条件? 如果是这样,怎么样?

[英]Is it possible to check a condition after every method in a loop? If so, how?

就像我在标题中说的那样,我在RPG中有一个关于高中的循环。 这是主要的循环,它按照时间顺序设置您的一天来执行单个序列。 我的问题是我怎么能这样做,以便我检查boolean “节拍”或boolean “丢失”(指游戏的状态)是否在循环中的每个方法之后被跳转到了真,但仍然将方法保持在一起在一个循环中。 嵌套在if循环中的if语句是唯一的方法吗?

while (!g.getBeat() || g.getLost()) 
{
    g.wakeUp();
    g.goToSchool();
    g.beforeLunch();
    g.lunchActivity();
    g.afterLunch();
    g.afterSchool();
    g.home();
    g.sleep();
}

你必须手动完成。 为了帮助您编写更少的代码,请创建一个检查两个条件的方法:

private boolean stopTheLoop() {
    return g.getBeat() || g.getLost();
}

现在,在每个方法之后使用检查将循环转换为无限:

while (true) {
    g.wakeUp();
    if (stopTheLoop()) break;
    g.goToSchool();
    if (stopTheLoop()) break;
    g.beforeLunch();
    if (stopTheLoop()) break;
    ...
}

您可以通过引入状态来使用switch语句:

int state = 0;
while (!g.getBeat() || g.getLost()) 
{
    switch (state) {
    case 0:
      g.wakeUp();
      break;
    case 1: 
      g.goToSchool();
      break;
    case 2: 
      g.beforeLunch();
      break;
    case 3: 
      g.lunchActivity();
      break;
    case 4: 
      g.afterLunch();
      break;
    case 5: 
      g.afterSchool();
      break;
    case 6: 
      g.home();
      break;
    case 7: 
      g.sleep();
      break;
    default:
      // some error handling, depending on your logic, 
      // or perhaps state = -1 to restart
    }
    state++;
}

没有任何“内置”方法可以做到这一点,但通过一些编码,一切皆有可能。

首先,无论你如何处理这个问题,我都会将结束条件包装到一个方法中,只是为了让事情变得更方便:

public class Game {
    // method, members, etc...

    public boolean isOver() {
        return !getBeat() || getLost();
    }
}

现在,想到的第一个选项是手动执行此操作:

while (!g.isOver()) {
    g.wakeUp();
    if (g.isOver()) {
        break;
    }
    g.goToSchool();
    if (g.isOver()) {
        break;
    }
    // etc...
}

但这涉及很多代码,而且不是太优雅。

或许更多的OO方法是在处理程序类中扭曲每个这样的调用:

public abstract GameStageHandler (Game g) {
    protected Game g;

    public GameStageHandler (Game g) {
        this.g = g;
    }


    /**
     * Play a stage in the game
     * @return Whether the game should go on or not after this stage
     */
    public boolean play() {
        performStage();
        return !g.isOver();
    }

    public abstract void performStage();
}

并为游戏的每个阶段实施它。 例如,对于wakeUp()阶段,你有:

public abstract WakeUpHandler (Game g) {
    public WakeUpHandler (Game g) {
        super(g);
    }

    @Override
    public void performStage() {
        g.wakeUp();
    }
}

然后,在main方法中,您可以拥有一个这样的处理程序数组,并迭代它们:

List<GameStageHandler> handlers = ...;
while (!g.isOver()) {
    for (GameStageHandler handler : handlers) {
        if (!g.play()) {
            break;
        }
     }
}

这可能超出了你的任务范围,因为你注意到该课程甚至还没有涵盖Runnable 然而,这是一个有趣的问题,挑战在于提出一种简洁而优雅的方式来表示它,同时避免尽可能多的重复。 这是一个使用Java 8和函数式编程技术的解决方案。

第一个见解是看到每个游戏动作或步骤可以表示为lambda表达式或方法引用。 我假设你有一个Game类。 每个这样的步骤都将Game实例作为参数(或接收者),因此可以键入Game实例的“消费者”。 因此我们可以将它们放入数据结构中:

List<Consumer<Game>> actions = Arrays.asList(
    Game::wakeUp,
    Game::goToSchool,
    Game::beforeLunch,
    Game::lunchActivity,
    Game::afterLunch,
    Game::afterSchool,
    Game::home,
    Game::sleep);

现在我们将它们放在数据结构中,我们可以遍历它们:

for (Consumer<Game> action : actions) {
    action.accept(game);
}

当然,我们想要检查每个动作后游戏是否结束。 假设你在Game类上有一个方法isOver来检查正确的终止条件。 然后你可以这样做:

for (Consumer<Game> a : actions) {
    a.accept(game);
    if (game.isOver()) {
        break;
    }
}

这只会持续一天的比赛。 大概你想要无限期地运行游戏,直到达到终止状态。 为此你需要一个外部循环,终止检查必须突破外部循环:

outer:
while (true) {
    for (Consumer<Game> a : actions) {
        a.accept(game);
        if (game.isOver()) {
            break outer;
        }
    }
}

这本身就足够了:你有一个游戏动作列表,一个无限运行的循环,检查每个动作后的终止条件。

但等等,还有更多! 这里仍然有相当数量的样板,可以使用Java 8的一些流功能来消除它们。 考虑使用noneMatch方法可以针对谓词测试流的每个元素。 当其中一个谓词返回true时,此方法终止。

由于每个动作都有类型Consumer<Game> ,我们需要一个小助手函数将每个动作转换为谓词:

static Predicate<Consumer<Game>> stepAndCheck(Game game) {
    return c -> { c.accept(game); return game.isOver(); };
}

现在我们可以按如下方式运行一天的所有操作:

actions.stream().noneMatch(stepAndCheck(game))

要无限期地运行游戏,我们只需将其包装在while循环中。 因为如果没有谓词匹配,所以如果noneMatch返回true ,那么我们将其设置为循环条件并将循环体留空:

while (actions.stream().noneMatch(stepAndCheck(game))) {
    // nothing
}

这可能看起来像是不必要地模糊不清。 事实上,对于像这样的玩具示例,它可能是。 但是,对于更复杂的问题,这样的技术非常有价值。

如果你想像你在你的例子中那样用自己的方法保持每一步,你几乎无能为力......

如果在满足停止循环的条件时使所有这些方法返回“true”,则可以减少代码量...但是,如果您计划在顺序上下文中使用这些方法,则可能无法实现。

if (!g.getBeat() || g.getLost()) do {
    if (g.wakeUp()) break;
    if (g.goToSchool()) break;
    ...
    if (g.sleep()) break;
} while (true);

一个可能的技巧是在满足停止条件时使这些方法抛出异常。 然后你会在循环外捕获该异常。 这样你就可以保存if(...)break语句。 然而,这不是一个好习惯。

if (!g.getBeat() || g.getLost()) {
  try {
    do {
      g.wakeUp();
      g.goToSchool();
      ...
      g.sleep();
    } while (true);
  } catch (ActivityLoopFinished ex) {
    // nothing to do here
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM