对于我的下一个例子,我将编写一个程序来实现一个简单的猜谜游戏,在这个游戏中,计算机生成一个随机数,人类玩家有10次机会猜测这个秘密数字。在每次猜测中,程序都会告诉用户他们的猜测是过高、过低还是正确。一旦玩家猜对了数字或猜完了10次,程序将不再接受猜测。
对于这个示例程序,我们将创建一个类型为Game的对象来运行猜谜游戏。Game对象将在内部存储一些状态信息,以跟踪游戏的进度,并提供允许人类玩家玩游戏的方法。
以下是Game类主要元素的概要。
公共类游戏{私有布尔gameOver;private int secretNumber;private int numberofattempts;public Game() {} public Game(int range) {} public boolean isGameOver() {} public void guess(int n) {}}
Game类有三个成员变量和四个方法。注意,没有一个方法是静态的——这是我们将用于创建对象的类中的方法的通常情况。
这三个成员变量构成了每个Game对象将包含的数据。这些成员变量允许Game对象跟踪游戏的进度。
的方法
public Game() {} public Game(int range) {}
都是构造函数。构造函数与类中的其他方法有两点区别:它们具有与类相同的名称,并且它们没有返回类型。构造函数的存在只有一个目的——它们的职责是确保对象的成员变量在对象创建的瞬间被正确初始化。
要在程序中创建一个对象,通常会编写如下代码:
myGame = new Game();
这个语句同时做了几件事。部分
游戏myGame
的语句声明一个变量。这个变量就是所谓的对象引用变量。它的主要目的是让你能够访问特定类型的游戏对象。简单地声明这样一个变量对创建对象没有任何作用。上面语句的后半部分负责这样做。(右侧出现关键字new表明我们正在创建一个新对象。)
同样在右边,我们看到一些看起来有点像方法调用的东西:
游戏()
这实际上是在调用一个方法,Game类的构造函数。调用构造函数方法将确保我们正在创建的新对象具有其成员变量的正确值。
下面是Game类的两个构造函数的代码。
public Game() {gameOver = false;secretNumber = (int) (Math.random() * 100 + 1);numberofguess = 0;}公共游戏(int范围){gameOver = false;secretNumber = (int) (Math.random() * range + 1);numberofguess = 0;}
第一个构造函数称为默认构造函数,它使用默认值初始化三个成员变量。缺省情况下,secretNumber生成1 ~ 100之间的随机整数。第二个构造函数允许调用者指定为secretNumber使用的范围:它将生成一个介于1和范围之间的秘密数字。例如,要创建一个秘密编号在1到20范围内的游戏对象,我们可以这样做:
游戏easyGame =新游戏(20);
除了构造函数之外,Game类还有另外两个方法。下面是这些方法的代码。
公共布尔isGameOver(){返回gameOver;}公共无效猜测(int n){如果(gameOver || numberofguess > 10){系统。游戏结束了。你不能再猜了。”} else if (n == secretNumber) {System.out。println(“你猜对了!”);gameOver = true;} else {if (n < secretNumber) {System.out。println(“你的猜测太低了。”);} else {System.out。println(“你的猜测太高了。”);} numberOfGuesses + +;如果(numberofguess == 10) {System.out。println(“你已经用完了赢博体育的猜测。”);gameOver = true;}}
isGameOver()方法询问一个Game对象它所代表的游戏是否已经完成。guess()方法将猜测提交给Game对象。当给定猜测时,Game对象将通过打印消息来响应,指示猜测是否正确、过高或过低。此外,每次我们调用Game的guess方法时,它都会更新其内部计数器numberofguess。如果numberofguessed在用户没有正确猜出秘密数字的情况下达到10,则Game对象声明游戏结束。
下面是一个单独类的代码,其中包含一个将玩游戏的主方法。
public class PlayGame {public static void main(String[] args){扫描器输入=新扫描器(System.in);Game = new Game();而(! theGame.isGameOver ()) {system . out。println(“猜测1到100之间的数字:”);int n = input.nextInt();theGame.guess (n);}}
请注意,游戏是通过将方法调用(如theGame.isGameOver()和theGame.guess(n))定向到我们创建的game对象来进行的。Game对象本身跟踪管理正在玩的游戏所需的赢博体育细节,所以我们只需要确保调用适当的方法来玩游戏。
关于Game类结构的最后一个评论。Game类的成员变量都声明为私有的。
私有布尔gameOver;private int secretNumber;private int numberofattempts;
通常,如果在类中创建成员变量并将其声明为public,则允许类外的代码直接访问该成员变量。例如,如果我们将secretNumber声明为public,则可以编写如下代码。
Game g = new Game();int goodGuess = g.secretNumber;g.guess (goodGuess);
通过直接访问Game对象内部以访问其secretNumber成员变量,我们使操纵游戏成为可能。显然,我们不允许这种事情发生。修复方法是简单地将secretNumber成员变量声明为私有。声明为私有的变量仍然可以被类方法的代码访问和使用,但是类之外的代码不能访问它们。
实际上,类外部的代码仍然可以通过调用方法间接访问对象中的数据。这实际上是首选的方法——这些方法有效地控制和调节对对象内部数据的访问,并有助于保证对象的内部状态始终得到良好的调节。
这种将内部数据隐藏在私有变量中并使用方法控制对数据的访问的策略被称为封装。在本课程剩下的大部分示例中,我将使用封装作为有意识的设计策略。