简体   繁体   English

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

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

Like I said in the title I have a loop in an RPG I'm making about High School. 就像我在标题中说的那样,我在RPG中有一个关于高中的循环。 This is the main loop that sets up your day to act out individual sequences in chronological order. 这是主要的循环,它按照时间顺序设置您的一天来执行单个序列。 My question is how could I make it so that I check whether the boolean "beat" or the boolean "lost" (referring to the status of the game) has been tripped to true after every method in the loop but still keeping the methods together in a loop. 我的问题是我怎么能这样做,以便我检查boolean “节拍”或boolean “丢失”(指游戏的状态)是否在循环中的每个方法之后被跳转到了真,但仍然将方法保持在一起在一个循环中。 Is nested if statements inside my while loop the only way? 嵌套在if循环中的if语句是唯一的方法吗?

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

You would have to do it manually. 你必须手动完成。 To help you write a little less code, make a method that checks both conditions: 为了帮助您编写更少的代码,请创建一个检查两个条件的方法:

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

Now convert your loop to infinite with checks after each method: 现在,在每个方法之后使用检查将循环转换为无限:

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

You could use a switch statement by introducing a state : 您可以通过引入状态来使用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++;
}

There isn't any "built-in" way to do this, but with some coding, anything's possible. 没有任何“内置”方法可以做到这一点,但通过一些编码,一切皆有可能。

First, regardless if how you handle this, I'd wrap the end condition into a single method, just to make things more convenient: 首先,无论你如何处理这个问题,我都会将结束条件包装到一个方法中,只是为了让事情变得更方便:

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

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

Now, The first option that comes to mind is to do this manually: 现在,想到的第一个选项是手动执行此操作:

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

But this involves a lot of code, and isn't too elegant. 但这涉及很多代码,而且不是太优雅。

A more OO approach, perhaps, would be to warp every such call in a handler class: 或许更多的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();
}

And implement it for every stage of the game. 并为游戏的每个阶段实施它。 Eg for the wakeUp() stage you'd have: 例如,对于wakeUp()阶段,你有:

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

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

Then, in the main method, you could have an array of such handlers, and iterate over them: 然后,在main方法中,您可以拥有一个这样的处理程序数组,并迭代它们:

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

This is probably beyond the scope of your assignment, as you noted the class hasn't even covered Runnable yet. 这可能超出了你的任务范围,因为你注意到该课程甚至还没有涵盖Runnable This is an interesting question, though, and the challenge is to come up with a concise and elegant way to represent it, while avoiding as much repetition as possible. 然而,这是一个有趣的问题,挑战在于提出一种简洁而优雅的方式来表示它,同时避免尽可能多的重复。 Here's a solution that uses Java 8 and functional programming techniques. 这是一个使用Java 8和函数式编程技术的解决方案。

The first insight is to see that each game action or step can be represented as a lambda expression or method reference. 第一个见解是看到每个游戏动作或步骤可以表示为lambda表达式或方法引用。 I'll assume that you have a Game class. 我假设你有一个Game类。 Each such step takes a Game instance as an argument (or receiver) and thus can be typed as a "consumer" of Game instances. 每个这样的步骤都将Game实例作为参数(或接收者),因此可以键入Game实例的“消费者”。 We can thus put them into a data structure: 因此我们可以将它们放入数据结构中:

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

Now that we have them in a data structure, we can loop over them: 现在我们将它们放在数据结构中,我们可以遍历它们:

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

Of course, we want to check if the game is over after each action. 当然,我们想要检查每个动作后游戏是否结束。 Let's assume you have a method isOver on the Game class that checks the right termination conditions. 假设你在Game类上有一个方法isOver来检查正确的终止条件。 You can then do: 然后你可以这样做:

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

That only runs through one day of the game. 这只会持续一天的比赛。 Presumably you want to run the game indefinitely until it reaches its termination condition. 大概你想要无限期地运行游戏,直到达到终止状态。 For that you need an outer loop, and the termination check has to break out of the outer loop: 为此你需要一个外部循环,终止检查必须突破外部循环:

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

This by itself might be sufficient: you have a list of game actions, and a loop that runs indefinitely, checking the termination condition after each action. 这本身就足够了:你有一个游戏动作列表,一个无限运行的循环,检查每个动作后的终止条件。

But wait, there's more! 但等等,还有更多! There's still a fair amount of boilerplate here, which can be eliminated using some of Java 8's stream features. 这里仍然有相当数量的样板,可以使用Java 8的一些流功能来消除它们。 Consider that every element of a stream can be tested against a predicate using the noneMatch method. 考虑使用noneMatch方法可以针对谓词测试流的每个元素。 This method terminates when one of the predicates returns true. 当其中一个谓词返回true时,此方法终止。

Since each action has type Consumer<Game> , we need a little helper function that turns each action into a predicate: 由于每个动作都有类型Consumer<Game> ,我们需要一个小助手函数将每个动作转换为谓词:

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

Now we can run all the actions of a day as follows: 现在我们可以按如下方式运行一天的所有操作:

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

To run the game indefinitely, we simply wrap this in a while loop. 要无限期地运行游戏,我们只需将其包装在while循环中。 Since noneMatch returns true if, as it says, none of the predicates matches, we make this the loop condition and leave the loop body empty: 因为如果没有谓词匹配,所以如果noneMatch返回true ,那么我们将其设置为循环条件并将循环体留空:

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

This might seem like it's unnecessarily obscure. 这可能看起来像是不必要地模糊不清。 Indeed, it might be, for toy examples such as this. 事实上,对于像这样的玩具示例,它可能是。 However, for more complex problems, techniques like this are quite valuable. 但是,对于更复杂的问题,这样的技术非常有价值。

If you want to keep each step in its own method like you do in your example there is little you can do about it... 如果你想像你在你的例子中那样用自己的方法保持每一步,你几乎无能为力......

You can reduce the amount of code if you make all those methods to return "true" if the condition to stop the loop is met... however this might not be possible if you plan to use those methods in order context. 如果在满足停止循环的条件时使所有这些方法返回“true”,则可以减少代码量...但是,如果您计划在顺序上下文中使用这些方法,则可能无法实现。

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

A possible trick is to make those methods to throw an exception if the stop condition is met. 一个可能的技巧是在满足停止条件时使这些方法抛出异常。 Then you would catch that exception in outside the loop. 然后你会在循环外捕获该异常。 That way you would save the if (...) break statements. 这样你就可以保存if(...)break语句。 However this is not considered a good practice. 然而,这不是一个好习惯。

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.

相关问题 设计 - 在执行每个方法之前检查条件 - Design - Check a condition before executing every method java-如何在每个方法上检查方法 - java - how to check a method on every method DBUnit不会在每个方法之后清理并插入数据库,因此测试不是独立的 - DBUnit not cleaning and insert the database after every method, so test are not independent 如何在for循环中检查条件并打印一次语句? - How to check condition in a for loop and print the statement once? 如何在有条件的循环中检查输入的字符串? - How to check entered String in a loop with condition? 如何解决声纳问题“正确性 - 此方法在找到相等条件后继续循环” - How to resolve the sonar issue “Correctness - This method continues a loop after finding an equality condition ” 如何随机化一个String数组,以便每次循环都不同 - How to randomize an array of a String so it is different every time though the loop 如何添加条件,这样我就不会在循环中使用 go - How to add a condition so I don't go inside the loop 如何在Java中每1秒检查一次某些条件,直到达到true - How to check some condition every 1 sec in java until true 如何使用lambda表达式向一个方法发送一个条件,以便它还没有被评估? - How to send a condition to a method using lambda expression so that it is not yet evaluated?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM