城堡游戏优化(二)以框架+数据来提高代码的可扩展性
在之前的文章JAVA学习笔记(五)城堡游戏的优化中,我们取消了代码的硬编码形式,而是使用框架,在Room类中建立了一个数据结构(哈希表),方向—房间的对应关系。还比如说我们创造了一些接口,setExit(),getExit()等等,避免了Game类对Room类的成员变量的直接调用。所以我们有了一种新的思路,尽量把硬编码形式改为使用框架+数据的形式来提高代码的可扩展性。那么我们也可以将命令(help,go,bye)的解析从硬编码形式改为框架+数据的形式。
if (words[0].equals("help")) {
game.printHelp();
}
else if ( words[0].equals("go")) {
game.goRoom(words[1]);
}
else if ( words[0].equals("bye")){
break;
}
我们可以创造三个函数,分别是help,go,bye来表示命令,用函数来执行命令。但是Hash表可以存放类但不能存放函数,所以我们可以定义一个Handler类来处理命令,用Hash表来保存命令与Handler之间的关系。
首先我们要先创造一个Handler父类,用来表示命令的类型,然后在Game里面new一个Hashmap对象,用来存放命令关键字key和命令的类。
private HashMap<String,Handler> handlers = new HashMap<String, Handler>();
创建好了以后我们就需要创建四个类,父类Handler和三个子类,HandlerHelp,HandlerGo和HandlerBye,分别表示查看帮助的命令,前往下一个房间的命令,以及游戏结束的命令。
Handler:
package castlegame;
public class Handler {
protected Game game;
public Handler(Game game){
this.game = game;
}
public void doCmd(String word){
}
public boolean isBye(){
return false;
}
}
HandlerHelp:
package castlegame;
public class HandlerHelp extends Handler{
public HandlerHelp(Game game){
super(game);
}
public void doCmd(String word){
System.out.println("迷路了吗?你可以做的命令有:go | bye | help");
System.out.println("如:\tgo east");
}
}
HandlerGo:
package castlegame;
public class HandlerGo extends Handler{
public HandlerGo(Game game){
super(game);
}
public void doCmd(String word){
game.goRoom(word);
}
}
HandlerBye:
package castlegame;
public class HandlerBye extends Handler{
public HandlerBye(Game game){
super(game);
}
public boolean isBye(){
return true;
}
}
我们可以看到在四个类中我们创建了一些函数,也定义了一些成员变量,还创造了一些构造器,我们一个一个慢慢来说。
首先我们在Game类中,把所以跟三个命令有关的代码都删除,在main函数里面只留下创造game对象,输出游戏开始界面的代码,然后新创建一个play()函数,用来运行游戏和执行命令。
public static void main(String[] args) {
Game game = new Game();
game.printWelcome();
game.play();
}
然后我们把之前本来存放在main函数里面的执行游戏的命令,放到play()函数里面,用函数来执行整个游戏。
public void play(){
Scanner in = new Scanner(System.in);
while (true) {
String line = in.nextLine();
String[] words = line.split(" ");
Handler handler = handlers.get(words[0]);
String value = "";
if ( words.length > 1 )
value = words[1];
if ( handler != null ){
handler.doCmd(value);
if ( handler.isBye() )
break;
}
}
System.out.println("***********************************");
System.out.println("游戏到此结束!");
System.out.println("欢迎下次光临!");
System.out.println("谢谢!");
System.out.println("***********************************");
in.close();
}
这里我们做了一些改动,首先是创造了一个handler对象,来让它等于我们输入的第一个字符串,只这样就相当于跳转到哈希表中我们相应要执行的命令,help对应help,go对应go,bye对应bye。再创建一个value对象来初始化为””。如果我们输入的字符串长度大于1,则使value等于我们输入的第二个字符串,此时的意思就是我们进行了GoRoom这个操作,也就是进入下一个房间,因为无论是help命令,还是bye命令,都是只有一个字符串的。如果第一个字符串不为null的话,则执行命令,也就是执行handler类的doCmd()函数。
在我们的三个handler子类的doCmd()函数中,分别执行的东西是不一样的。在HandlerHelp中执行的是输出帮助的一些语句,在go中是跳转到下一个房间,在bye中是返回一个布尔值,返回true并使循环结束,游戏结束并输出游戏结束的一些语句。那么我们就要在Game()对象中把对应的字典存放到哈希表里面了。
public Game()
{
handlers.put("go",new HandlerGo(this));
handlers.put( "bye",new HandlerBye(this));
handlers.put("help",new HandlerHelp(this));
createRooms();
}
因为我们在HandlerGo类里面的doCmd()函数中,需要调用到Game类里面的goRoom()函数,所以我们需要在Handler父类中protected一个Game对象,创建构造器,并在所有的子类中都创建一个构造器,用super()来得到父类中的Game对象,这样我们才可以在子类中调用到Game类中的函数,同时需要在Game类的Game()对象中,创建哈希表时,输入一个this,把这个对象给到所有的Handler子类中。这样我们就完成了代码的扩展。以下是Game和Room类的完整代码(四个Handler类的代码在上面):
Game:
package castlegame;
import java.util.HashMap;
import java.util.Scanner;
public class Game {
private Room currentRoom;
private HashMap<String,Handler> handlers = new HashMap<String, Handler>();
public Game()
{
handlers.put("go",new HandlerGo(this));
handlers.put( "bye",new HandlerBye(this));
handlers.put("help",new HandlerHelp(this));
createRooms();
}
public void play(){
Scanner in = new Scanner(System.in);
while (true) {
String line = in.nextLine();
String[] words = line.split(" ");
Handler handler = handlers.get(words[0]);
String value = "";
if ( words.length > 1 )
value = words[1];
if ( handler != null ){
handler.doCmd(value);
if ( handler.isBye() )
break;
}
}
System.out.println("***********************************");
System.out.println("游戏到此结束!");
System.out.println("欢迎下次光临!");
System.out.println("谢谢!");
System.out.println("***********************************");
in.close();
}
private void createRooms(){
Room pub,lobby,study,bedroom,bedroom1;
//创造房间
pub = new Room("小酒馆");
lobby = new Room("大厅");
study = new Room("书房");
bedroom = new Room("卧室");
bedroom1 = new Room("次卧");
//设置出口
pub.setExit("east", lobby);
lobby.setExit("south" ,study);
lobby.setExit("west" ,pub);
lobby.setExit("east" ,bedroom1);
study.setExit("north", lobby);
study.setExit("east", bedroom);
bedroom.setExit("west", study);
bedroom1.setExit("west",lobby);
currentRoom = pub;
}
public void printWelcome(){
System.out.println("***********************************");
System.out.println("欢迎来到城堡游戏!");
System.out.println("这是一个超级无聊的小游戏。");
System.out.println("如果需要帮助,请输入help。");
System.out.println("那么我们开始游戏吧!");
System.out.println("***********************************");
System.out.println("现在你在"+currentRoom);
showPrompt();
}
private void showPrompt(){
System.out.println("你在"+ currentRoom);
System.out.println("出口有:");
System.out.println(currentRoom.getExitDesc());
}
public void goRoom(String direction) {
Room nextRoom = currentRoom.getExit(direction);
if(nextRoom == null){
System.out.println("那里没有门!");
}
else{
currentRoom = nextRoom;
showPrompt();
}
}
public static void main(String[] args) {
Game game = new Game();
game.printWelcome();
game.play();
}
}
Room:
package castlegame;
import java.util.HashMap;
public class Room {
private String description;
private HashMap<String,Room> exits = new HashMap<String, Room>();
public Room(String description) {
this.description = description;
}
public void setExit(String direction,Room room){
exits.put(direction,room);
}
public String toString()
{
return description;
}
public String getExitDesc(){
StringBuffer sb = new StringBuffer();
for ( String direction : exits.keySet() ){
sb.append(direction);
sb.append(' ');
}
return sb.toString();
}
public Room getExit(String direction){
return exits.get(direction);
}
}