5.5 框架加数据

从程序中识别出框架和数据,以代码实现框架,将部分功能以数据方式加载,这样在很大程度上实现了可拓展性.

以框架+数据来提高可拓展性

●命令的解析是否可以脱离 if - else

●定义一个Handler来处理命令

●用Hash表来保存命令&Handler之间的关系

我们之前刚开始城堡游戏做的是硬编码,就是把方向什么都当作Room的成员变量,然后调用,后来我们利用HashMap函数, 将方向和房间联系起来,这样我们就可以随意的增加不同的方向,

我们也利用接口函数,传入数据,返回数据,这些我们形成了一个框架,在这些框架里面,我们如果要增加新的出口,  很容易.

所以这是一种思路,  把程序的硬编码,  尽可能的分解成框架和数据的结构, 框架规定说,我们有一个HashMap , 我们有这几个接口函数,  数据就是我们放在HashMap里面的东西.

那么在这个程序里面,  还有一部分是硬编码. 就是我们的命令解析 ,  我们现在有三个变量

"go" ,"help ", "bye".

我们在Game的主函数里面 , 有一个判断输的字符

 这是一种硬编码, 当然我们的HashMap  里面存放的是键值和元素,都必须是对象, 而我们这里需要的是,  输入字符串, 然后去调用函数, 函数不是对象.

那类里面可以有函数, 所以我们可以定义一个新的类

public class Handler{
    public void doCmd(String word){}
}

我们这是为不同操作定义的一个基础类

那接下来, 我们要定义一个对象,用来保存 字符串 和 Handler对象之间的对应关系

在Game里面,定义成员变量

    private HashMap<String , Handler>  handlers = new HashMap<String , Handler>();

当然我们想将输入的"help"  "go"  "bye "  和对应的操作联系起来, 需要在HashMap里面创建对象,

那我们需要在Game初始化的时候,就把对象填进去, 那我们就那Game的构造函数开刀.

public Game(){
        handlers.put("bye" , new HandlerBye(this));

        handlers.put("help" , new HandlerHelp(this));

        handlers.put("go" , new HandlerGo(this));

        createRooms();

    }

我们new 创建了一个关于HadlerGo 、HandlerBye 、HandlerHelp的类的对象

那我们就需要创建这几个类,来实现调用相关的指令

开始之前 , 我们还需要把主函数里面的判断输入,调用函数的工作 , 去交给成员函数

你叉叉


替换成     game.play();

 交给成员变量:

public void play(){
  Scanner in = new Scanner(System.in);
  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;
        		}
    }
}

此时,如果我们要根据输入的字符串 , 来调用指定的对象的类的操作, 就需要我们的 handler了

public void play(){
  Scanner in = new Scanner(System.in);
  while ( true ) { 
                String line = in.nextLine();
                String[] words = line.split(" ");
                Handler handler = handlers.get(word[0]);
                if( handler != null){
                    handler.doCmd(word[1]);
                        if( handler.isBye())
                            break;

                }
    }
}


所以, 我们结束的时候,需要 Handler 类里面有一个成员函数

public boolean isBye(){  return false ;}

默认返回 false


那什么时候返回true 呢,就是结束的时候, 我们可以让另一个 HandlerBye 类来继承Handler类,然后我们就可以覆盖 父类的public boolean isBye(){  return false ;} 成员函数了 

定义的Handler类,

父类

public class Handler{
    public void doCmd(String word){}
    public boolean isBye(){ return false;}
}

子类继承父类

public class HandlerBye extends Handler{
	
	@Override
     public boolean isBye(){
		return true;

     }
}

那现在我们要实现 , 输入bye , 然后就调用对应容器里的函数, 需要我们在容器 handlers里面放入   字符串bye 和HandlerBye 对象之间的关系

在Game的构造函数里面

public Game(){

        handlers.put("bye" , new HandlerBye());

}


因为我们需要用到handlerBy 这个类的属性,所以要创建一个对象,然后将这个对象放在容器handlers里面,容器里面放的是字符串和对象之间的关系

这里,

 当我们输入 “bye”  的时候, 第一个单词就是,然后 

Handler  handler = handlers.get("bye");

把容器里面的 bye对应的 HandlerBye 对象传递给了 handler ,  变成

if(HandlerBye != null){

    HandlerBye.doCmd(words[1]);

    if(HandlerBye.isBye())    / /调用了Handler的子类HandlerBye覆盖了public booleanisBye()

    {                 

          beak ;                            //返回了true,然后结束了游戏                                        

    }

那我们其他命令,比如 go east  go west ,是第二个字符,我们也要进行赋值,怎么办,我们做了一点小修改

public void play(){
    	 @SuppressWarnings("resource")
		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;
			 }
    	 }
   }

现在 bye 命令可以用了,但是 help 还是不能用的

我们要覆盖Handler类的 doCmd 成员函数

HandlerHelp类


public class HandlerHelp extends Handler{

	@Override
    
    public void doCmd(String word){
          System.out.println("迷路了吗?你可以做的命令有: go bye help");

          System.out.println("如: \tgo east");

    }

}

Game 里面的  printHelp成员函数就不存在了

要让help起作用

我们需要在Game里面的handlers容器里面,放入

 handlers.put("help" , new HandlerHelp(this));

自然的,当我们输入 help 的时候

public void play(){
  Scanner in = new Scanner(System.in);
  while ( true ) { 
                String line = in.nextLine();
                String[] words = line.split(" ");
                Handler handler = handlers.get(word[0]);
                String value = "";
                if(words.length > 1)
                    value = word[1];
                if( handler != null){
                    handler.doCmd(value);
                        if( handler.isBye())
                            break;
                }
    }
}


handlers.get("help")  对应 对象HandlerHelp()

然后Handler的子类HandlerHelp就会调用  doCmd 函数,覆盖父类,输出帮助信息。

同理,我们接下来,给 go 添加操作

我们让HandlerGo继承 Handler,然后覆写

public  class HandlerGo extends  Handler{

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

     }

}

我们现在要的是,实现Game里面的goRoom 成员函数的功能,如果这里game 是指针的话,这种方法是可以的,我们需要拿到的是game的对象。

由于,作者能力有限,这里我们采用比较曲折的办法,

我们首先在Handler里面定义Game 的变量

public class Handler{
    

    protected Game game;

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

    }


    public void doCmd(String word){}

    public boolean isBye(){ return false;}

}

接下来,他的每一个子类都需要实现 ,带有Game的构造函数

public class HandlerBye extends Handler{

       

public HandlerBye(Game game) {
		super(game);
		// TODO Auto-generated constructor stub
	}

        @Override

        public boolean isBye(){

        return true;

        }

}

HandlerHelp 类:


public class HandlerHelp extends Handler{

       

    public HandlerHelp(Game game) {
		super(game);
		// TODO Auto-generated constructor stub
	}

        @Override

        public void doCmd(String word){

              System.out.println("迷路了吗?你可以做的命令有: go bye help");

              Sysem.out.println("如: \tgo east");

        }

}

那对于go来说,也会记下Game

HandlerGo类

public class HandlerGo extends Handler{

       

    public HandlerGo(Game game){
          super(game);

	 }

        public void doCmd(String word){

                        game.goRoom(word);

          }

}

还有一个问题,我们在各个类创建构造函数的时候,需要传入参数,我们在

Game 的构造函数里面,往容器里面传入 字符串和  用各个类创建的对象  赋予对应关系的时候, 在括号里传入(this)就可以了。

     public Game(){
        handlers.put("bye" , new HandlerBye(this));

        handlers.put("help" , new HandlerHelp(this));

        handlers.put("go" , new HandlerGo(this));

        createRooms();

    }

当然,为了让我们能调用Game里的 goRoom成员函数,我们需要将private 改成 public ,这样我们就可以调用,并传入参数了 ,接着覆写函数了。

做完这个之后,如果我们的代码今后想要增加新的命令,我们需要做到事情只有两个地方,

第一,要有新的指令的 Handler类型

第二,在Game的构造器里面,把新的指令Handler对象放进去


然后,在public void play { }里面的代码不需要改变,这就是可扩展性。

我们之所以把操作分开进行输入,是为了尽可能让每一个指令形成一个类,尽可能聚合,让功能更清晰。

源代码如下:

Game类:

package castle;
 
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("bye" , new HandlerBye(this));

        handlers.put("help" , new HandlerHelp(this));

        handlers.put("go" , new HandlerGo(this));

        createRooms();

    }

    private void createRooms()
    {
        Room outside, lobby, pub, study, bedroom;
      
        //	制造房间
        outside = new Room("城堡外");
        lobby = new Room("大堂");
        pub = new Room("小酒吧");
        study = new Room("书房");
        bedroom = new Room("卧室");
        
        //	初始化房间的出口
		outside.setExit("east" , lobby);
 
		outside.setExit("south", study);
 
		outside.setExit("west", pub);
 
		lobby.setExit("west" , outside);
 
		pub.setExit("east" , outside);
 
		study.setExit("north" , outside);
 
		study.setExit("east" , bedroom);
 
		bedroom.setExit("west" , study);
 
		lobby.setExit("up" , pub);
 
		pub.setExit("down" , lobby);
 
        currentRoom = outside;  //	从城堡门外开始
    }
 
    private void printWelcome() {
        System.out.println();
        System.out.println("欢迎来到城堡!");
        System.out.println("这是一个超级无聊的游戏。");
        System.out.println("如果需要帮助,请输入 'help' 。");
        System.out.println();
        showPrompt();
    }
 
    // 以下为用户命令
 
    private void printHelp() 
    {
        System.out.print("迷路了吗?你可以做的命令有:go bye help");
        System.out.println("如:\tgo east");
    }
 
    public void goRoom(String direction) 
    {
        Room nextRoom = currentRoom.getExit(direction);
        if (nextRoom == null) {
            System.out.println("那里没有门!");
        }
        else {
            currentRoom = nextRoom;
            showPrompt();
        }
    }
    public void play(){
    	 @SuppressWarnings("resource")
		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;
			 }
    	 }
   }
	public void showPrompt(){
 
				System.out.println("现在你在" + currentRoom);
		        System.out.print("出口有:");
		        System.out.println(currentRoom.getExitDesc());		        
		        System.out.println();
	}
	public static void main(String[] args) {
		
		Game game = new Game();
		game.printWelcome();
		game.play();
        
        System.out.println("感谢您的光临。再见!");
     
	}
 
}

Room类:

package castle;
 
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 dir, Room room){
         exits.put(dir, room);
 
	}
    
    @Override
    public String toString()
    {
        return description;
    }
   
	public String getExitDesc(){
        StringBuffer   sb = new  StringBuffer();
        for( String dir : exits.keySet()){
                sb.append(dir);
 
                sb.append(' ');
        }
        return sb.toString();
	}
 
	public Room getExit(String direction){
		  return exits.get(direction);
	}
}

Handler类:

package castle;

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 castle;

public class HandlerHelp extends Handler{
	public HandlerHelp(Game game) {
		super(game);
		// TODO Auto-generated constructor stub
	}

	@Override
    
    public void doCmd(String word){
          System.out.println("迷路了吗?你可以做的命令有: go bye help");

          System.out.println("如: \tgo east");

    }

}

HandlerBye类:

package castle;

public class HandlerBye extends Handler{
	
	public HandlerBye(Game game) {
		super(game);
		// TODO Auto-generated constructor stub
	}
	@Override
     public boolean isBye(){
		return true;

     }
}

HandlerGo类:

package castle;

public  class HandlerGo extends  Handler{
	 public HandlerGo(Game game){
          super(game);

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

     }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值