利用封装、继承对Java代码进行优化

注:本文实例分别可以在oldcastle(未优化的代码)和newcastle(优化后的代码)中查看,网址见文末

城堡游戏:

城堡中有多个房间,用户通过输入north, south, east, west等来确认去哪一个房间(此时窗口会有提示转到哪个房间),如果此时多出一个房间,需要使用up, down才能到达,修改代码则需要代码具有可扩展性,对原来的代码进行优化来实现这个功能。

优化前代码思路:

利用封装、继承对Java代码进行优化

优化变量使代码具有可扩展性

主要思想:

  • Room中变量全部变为private类型,使代码变得安全。

  • 利用Hash表将方向变量实现灵活性。

    private HashMap<String, Room> exits = new HashMap<String, Room>();
    

    本文Hash表用到的方法:

    HashMap<Key, Value>
    HashMap.keySet()	// 返回所有的key值
    HashMap.put(K, V)	// 用于往HashMap中加元素
    HashMap.get(K)		// 返回对应的V值
    

利用封装降低代码间耦合性

主要思想:

​ 给Room类实现新方法,把方向的细节彻底隐藏在Room类内部,增添的方向与外部无关。

先看这段代码,在Game中出现了2次。

/*Game.java*/
/*在printWelcome, goRoom中需要显示当前和选择时*/
System.out.println("现在你在" + currentRoom);
System.out.print("出口有:");
if(currentRoom.northExit != null)
    System.out.print("north ");
if(currentRoom.eastExit != null)
    System.out.print("east ");
if(currentRoom.southExit != null)
    System.out.print("south ");
if(currentRoom.westExit != null)
    System.out.print("west ");
System.out.println();

修改思路:

Game类中添加显示出口的方法:

/*Game.java*/
public void showPrompt(){
  	System.out.println("现在你在" + currentRoom);
	System.out.print("出口有:");
	/*打印所有出口,getExitDesc()是Room中记录出口的新方法*/
	System.out.println(currentRoom.getExitDesc());	
	System.out.println();
}

Room类增加getExitDesc()方法:

/*Room.java*/
public String getExitDesc() {
    StringBuffer sb = new StringBuffer();	// StringBuffer类是字符串变量,常用于对字符串扩充和修改
    for (String dir : exits.keySet()) {		// 遍历所有的方向
        sb.append(dir);						// 扩充操作
        sb.append(' ');
    }
    return sb.toString();
}

goRoom中的转移房间代码与RoomsetExit有极高的耦合性:

/*Game.java*/
private void goRoom(String direction) {
  	Room nextRoom = null;
	if (direction.equals("north")) {
      nextRoom = currentRoom.northExit;
    }
    if (direction.equals("east")) {
      nextRoom = currentRoom.eastExit;
    }
    if (direction.equals("south")) {
      nextRoom = currentRoom.southExit;
    }
    if (direction.equals("west")) {
      nextRoom = currentRoom.westExit;
    }
}

/*Room.java*/
public void setExits(Room north, Room east, Room south, Room west) 
{
    if(north != null)
      northExit = north;
    if(east != null)
      eastExit = east;
    if(south != null)
      southExit = south;
    if(west != null)
      westExit = west;
}

修改思路

Room类修改setExit方法,并增加getExit方法。

/*Room.java*/
/*	
 * 录入房间空间位置的方式改变,由原来的对一个房间的四个方向分别定义,改为对一个房间
 * 自定义方向以及该方向上  的新房间,这样有利于增添上下以及新的位置,具有可扩展性。
 */
public void setExit(String dir, Room room) {
    exits.put(dir, room);			// 向exit中添加元素
}

public Room getExit(String direction) {
    return exits.get(direction);	// 返回对应的Room
}

Room修改之后对goRoom的修改就简单许多:

/*Game.java*/
private void goRoom(String direction) {
  	Room nextRoom = null;
	Room nextRoom = currentRoom.getExit(direction);
}

以框架+数据以及继承提高可扩展性

对于Gamemain方法存在这样一段代码:

public static void main(String[] args) {
    while (true) {
        String line = in.nextLine();
        String[] words = line.split(" ");
        if (words[0].equals("help")) {
          game.printHelp();
        } else if (words[0].equals("go")) {
          game.goRoom(words[1]);
        } else if (words[0].equals("bye")) {
          break;
        }
    }
}

思考:能否脱离if-else来实现用户的命令。

修改思路之创造新的类

定义一个Handler类来处理命令,用户命令分为go, help, bye三类,此时用Hash表来保存用户命令与Handler之间的关系,则Handler需要三个子类分别处理三种命令:
利用封装、继承对Java代码进行优化

/*Handler.java*/
public class Handler {
  	/*为了解决在HandlerGO操作中需要用到main方法里game,在Handler中创建Game来记录Game.java里的game.*/
    protected Game game;

    public Handler(Game game){
        this.game = game;
    }

    public void doCmd(String word) {
    }

    public boolean isBye() {
        return false;
    }

    public boolean isHelp() {
        return false;
    }
}

/*HandlerGo.java*/
public class HandlerGo extends Handler {
    public HandlerGo(Game game) {
        super(game);
    }

    @Override
    public void doCmd(String word) {
        game.goRoom(word);
    }
}

/*HandlerHelp.java*/
public class HandlerHelp extends Handler {
    public HandlerHelp(Game game) {
        super(game);
    }

    @Override
    public boolean isHelp() {
        return true;
    }
}

/*HandlerBye.java*/
public class HandlerBye extends Handler {
    public HandlerBye(Game game) {
        super(game);
    }

    @Override
    public boolean isBye() {
        return true;
    }
}
/*Game.java*/
/*用Hash表保存命令与Handler之间的关系*/
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(" ");
    	/*
    	 * 利用Hash表<K, V>的特性,如果用户输入"help",通过handler.get()得出handler类型
    	 * 下面这句就相当于:Handler handler = new HandlerHelp(this);
    	 */
        Handler handler = handlers.get(words[0]);
        String value = "";
        if(words.length > 1)
          	value = words[1];
        if(handler != null)
        {
          	/*此时handler为HandlerHelp型,没有value值*/
            handler.doCmd(value);
            if(handler.isBye())
              	break;
          	/*HandlerHelp继承了Handler中的isHelp()方法并将其覆盖,此时handler.isHelp()返回true.*/
            if(handler.isHelp())
              	this.printHelp();
        }
    }
}

public static void main(String[] args) {
    Game game = new Game();
    game.printWelcome();
    game.play();
}

源代码可以这个网页查看:

github/duyue6002/城堡游戏