我是一年级CS学生。我们目前正在学习Java,我的最新任务是创建这个随机数游戏。我希望获得有关代码样式等的一些反馈,以便我知道将来不应该做的事情,以便避免从一开始就养成不良习惯。我不太了解,所以任何解释/提示都将是惊人的! />

评论

对于初学者来说,这是相当不错的。我想你会好的。欢迎使用代码审查!

我很难不对使用K&R支撑的格式良好的代码发表评论。哦,等等,我就是这样。 :)对于初学者来说确实不错! :D

@Almo Allman是必去之路

#1 楼

未使用的导入-警告

您正在使用Eclipse。 Eclipse和NetBeans是IDE的IDE,它们可能会(除了将它们关闭之外)还向您发出有关代码的警告。不要使用Main。因此,您应该删除它。

您的IDE会不时给您其他警告。如果您看一下它给您的警告,它将对调试(“嘿,您在这里在null变量上调用函数!”)和清理代码(“使用java.util.Random代替String.isEmpty()”-我知道NetBeans甚至只允许您单击一个按钮,它就会为您修复。)

重复代码-重构

只要有可能,请尽量不要多次声明。

执行此功能。

public boolean guess(int guess) {
    tries++;
    if (guess == randomNumber) {
        if (tries > 1) {
            System.out.println("You got the number in " + tries + " tries.");
            return true;
        } else {
            System.out.println("You got the number in " + tries + " try.");
            return true;
        }
    } else if (guess > randomNumber) {
        System.out.println("Too high try again");
        return false;
    } else if (guess < randomNumber) {
        System.out.println("Too low try again ");
        return false;
    }
    return false;
}


应该做什么:


增加尝试次数乘以1。如果猜测正确,则报告尝试次数。如果猜测不正确,请报告该数字是低于还是高于隐藏数字。如果猜测正确,则返回true;如果猜测不正确,则返回false。


现在,您只是将一个int与另一个int进行比较,因此无需将string == ""定义为但是,我们可以做的是从分支中删除重复的代码。

        if (tries > 1) {
            System.out.println("You got the number in " + tries + " tries.");
            return true;
        } else {
            System.out.println("You got the number in " + tries + " try.");
            return true;
        }


该代码可以变成这样:
/>
if (tries > 1) {
    System.out.println("You got the number in " + tries + " tries.");            
} else {
    System.out.println("You got the number in " + tries + " try.");
}
return true;


由于它是一个简单的字符串,您可以做的另一件事是使用三进制:

System.out.println("You got the number in " + tries + ((tries > 1) ? " tries." : " try."));
return true;


对于“太高,太低的部分”也可以做类似的事情。

但这是另一种特殊情况...

如果数字不等于且不小于到某个值,那么显然它必须大于该值。

因此代码


if(is equal){
  print got number in x tries
  return true
} else if(is lower){
  print try higher
  return false
} else if(is higher){
  print try lower
  return false
}


最终的代码片段看起来像这样:

if(is equal){
  print got number in x tries
  return true
} else if(is lower){
  print try higher
  return false
} else {
  print try lower
  return false
}


您甚至可能要考虑将整个消息打印导出到单独的功能:值:

public boolean guess(int guess) {
    tries++;
    if (guess == randomNumber) {
        System.out.println("You got the number in " + tries + ((tries > 1) ? " tries." : " try."));
        return true;
    } //implicit else because return would end the function

    if (guess > randomNumber) {
        System.out.println("Too high try again");
    } else {
        System.out.println("Too low try again ");
    }
    return false;
}


将大型功能转换为几个较小的功能,每个功能都比起初使用的原始功能更容易掌握。

评论


\ $ \ begingroup \ $
我个人认为printTooHigh是过多的功能拆分。
\ $ \ endgroup \ $
– Almo
2014年10月31日,下午3:22

\ $ \ begingroup \ $
@Almo现在还可以,但是稍后您将不得不使某种消息框出现,或者出现i18n问题,或者不仅仅是一个打印语句。无论如何,通过提取函数,我们可以使guess函数在单个抽象级别上运行-情况1做到了,情况2做到了,情况3做到了,而不是混合了函数调用和print语句。
\ $ \ endgroup \ $
– Pimgd
14-10-31在8:23

\ $ \ begingroup \ $
非常感谢您的答复。您对如何缩短收益的解释很有帮助。另外,感谢您向我展示了三元数据,我之前从未听说过,不过将来肯定会使用它!
\ $ \ endgroup \ $
– jjacobson
2014年10月31日上午11:02

\ $ \ begingroup \ $
@jjacobson请记住,三元仅用于诸如此类的简单事情;通过非常快速地包含三元,代码会变得非常复杂。
\ $ \ endgroup \ $
– Pimgd
2014年10月31日在11:05

\ $ \ begingroup \ $
@Pimgd感谢您的注意。我将仔细阅读它们,以便可以正确使用它们。
\ $ \ endgroup \ $
– jjacobson
2014年10月31日11:10



#2 楼

这是您计划要做的一个很好的实现。事物的命名很清楚,并且代码可以很好地拆分为方法。

主类

我可能会对用户的预期进行更清晰的解释一开始要做的事情,以及您的“输入上限”。通常,这是打破您最好的ascii艺术的借口。

如果您的用户不输入整数,该怎么办?这将破坏您的程序,因此请进行一些错误处理,请您容易出错的肉包再次尝试并使其正确。您的检查方法是将scan.nextInt()放在try / catch块中并捕获InputMismatchException

当您问玩家是否要再次玩时,请将running设置为true,但是

游戏类

每次调用rand时,您都在播种generateRandomNumber(),这并不是真的成为一个问题,因为您没有快速/经常调用该方法,但实际上您应该只在程序中播种一次随机数生成器,否则您将一遍又一遍地开始让它返回相同的值,因此也许将您的Random rand = new Random()移至构造函数?

guess()中,我将第一部分重新排列为:

 if (guess == randomNumber) {
        if (tries > 1) {
            System.out.println("You got the number in " + tries + " tries.");
        } else {
            System.out.println("You got the number in " + tries + " try.");
        }
        return true;
 }


您在重复减少自己的负担,返回值相同。下一部分也一样,我将有:

 else if (guess > randomNumber) {
        System.out.println("Too high try again");
    } else if (guess < randomNumber) {
        System.out.println("Too low try again ");
    }
    return false;


评论


\ $ \ begingroup \ $
“如果您的用户不输入整数,该怎么办?”您会收到一个InputMismatchException。
\ $ \ endgroup \ $
– Pimgd
14-10-30在10:26

\ $ \ begingroup \ $
非常感谢您的答复。我曾考虑过用户输入错误的信息,并问我的教授是否应该牢记这一点。自从我们的第一个项目以来,他告诉我这次不必担心。否则我肯定会做到这一点。
\ $ \ endgroup \ $
– jjacobson
2014年10月31日10:50

#3 楼

这对我来说看起来不错。我特别喜欢Game是它自己的类。这是正确的决定,所以做得很好。在这种情况下,这意味着不写入Game;将输出上移至System.out,您也正在执行输入。尽管在像这样的小程序中并没有太大的区别,但它通常会导致可重用,可测试的代码,并且是进入代码的一种好习惯。

现在,您可以使main最终。这意味着一旦分配给它,其值就无法更改。它使您的意图对阅读您的代码的人很清楚,并且编译器会告诉您是否违反了该规则。

#4 楼

由于多余使用了两个标志变量main()win,因此running函数笨拙。通常,使用标志变量来控制执行流是不好的样式。还有更多更自信的方法可以到达目的地:


要运行游戏至少一次,然后可能一次又一次地使用do-while循环。
在可行的情况下,编写循环条件以执行正确的测试。

恰好三个分支之一必须申请。 (您最终的Game.guess()应该是不可访问的。)“ try”的多元性可以看作是要通过return false;解决的国际化问题。 (相对于某些其他语言,英语的复数形式比较简单。MessageFormat为应对这种复杂性作了更好的准备。您不妨利用为解决复数问题而构建的内置库。)

public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);
    System.out.println("Please enter the upper limit: ");
    Game game = new Game(scan.nextInt());

    do {
        game.reset();
        System.out.println("Please enter a guess ");

        while (!game.guess(scan.nextInt())) {
            // Loop until a correct guess
        }

        System.out.println("Would you like to play again y/n?");
    } while (scan.next().equalsIgnoreCase("y"));
    System.out.println("Game over");
}


#5 楼

不错的开始!

您应该将所有游戏控制逻辑移至Game,以便您的主循环为

while (!game.isGameOver())
{
     game.nextMove()
}


您可以编写代码“你想玩另一个吗?”很好地超出了这个循环。因此,Player会要求Game作为输入:

class Game
{
    public Game (Player p)
    {
        player = p;
    }

    Player player;
    public void nextMove()
    {
        //or something similar
        guess(player.getNextInput());
    }
}


您可以将所有IO(Player等)移至System.out类,因为Player不需要了解

现在,您可以轻松实现GameTestPlayer,而无需更改游戏逻辑中的任何内容。

由于AIPlayer是游戏逻辑,它应该返回guess()知道,并通知玩家。例如Game,其中可能包含一些代码(枚举),变量和一条消息。

   public MoveResult 
   {
      public static enum {TOO_HIGH, TOO_LOW, RIGHT}
      String message;
   }


MoveResult

    public void nextMove()
    {
        //or something similar
        MoveResult result = guess(player.getNextInput());
        player.notify(result);
    }


#6 楼

我的第一印象是您的代码看起来不错:简洁一致的样式,合理的方法长度,良好的变量名。唯一让我惊讶的事情(其他人没有提到)完全没有文档。

当您是唯一一个从事快速,小型项目的开发人员时,可以省略评论。当您进行长期项目时,或者与其他开发人员一起工作时,应该使用经过深思熟虑的文档。我写的文档为我(和我的同事)节省了比我花费更多的时间。在编写该程序时,我会重新考虑程序并经常发现设计中的缺陷,然后可以对其进行改进(请参阅橡皮鸭调试)。在您仍在学习时养成良好的习惯将是有益的。至于文档的内容,请阅读您使用的任何库的Javadocs(尤其是从Sun / Oracle和Apache之类的大型提供程序中)。

评论


\ $ \ begingroup \ $
您可以通过添加一些代码和更多参考来改善您的答案。
\ $ \ endgroup \ $
–bhathiya-perera
2014年10月31日15:16