java进阶2:类的关系、代码优化—城堡游戏、抽象与接口

文章目录


一、类的关系

技巧:自动创建构造器——

Alt

1. 继承

  • 事例:媒体资料库

Database

import java.util.ArrayList;

public class Database {
	
  //代码复制严重
	private ArrayList<CD> listCD = new ArrayList<CD>(); 
	private ArrayList<DVD> listDVD = new ArrayList<DVD>(); 
	
	//添加CD信息
	public void add(CD cd) {
		listCD.add(cd);
	}
	public void add(DVD dvd) {//函数重载
		listDVD.add(dvd);
	}
	
	//输出所有CD的信息
	public void list() {
		for(CD cd : listCD) {
			cd.print();
		}
		for(DVD dvd : listDVD) {
			dvd.print();
		}
	}
	

	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Database db = new Database();
		//子类对象可以当作父类的对象使用
		db.add(new CD("从前有1首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new CD("从前有2首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new CD("从前有3首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new CD("从前有4首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new DVD("我的**之旅", "霞基巴.卞德", 60, "好好看!"));
		db.list();
	}

}

CD

import java.util.ArrayList;

public class Database {
	
  //代码复制严重
	private ArrayList<CD> listCD = new ArrayList<CD>(); 
	private ArrayList<DVD> listDVD = new ArrayList<DVD>(); 
	
	//添加CD信息
	public void add(CD cd) {
		listCD.add(cd);
	}
	public void add(DVD dvd) {//函数重载
		listDVD.add(dvd);
	}
	
	//输出所有CD的信息
	public void list() {
		for(CD cd : listCD) {
			cd.print();
		}
		for(DVD dvd : listDVD) {
			dvd.print();
		}
	}
	

	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Database db = new Database();
		db.add(new CD("从前有1首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new CD("从前有2首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new CD("从前有3首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new CD("从前有4首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new DVD("我的**之旅", "霞基巴.卞德", 60, "好好看!"));
		db.list();
	}

}

DVD

public class DVD {//同CD

	private String title;
	private String director;
	private int playingTime;
	private boolean gotIt = false;
	private String comment;
	
	public DVD(String title, String director, int playingTime, String comment) {
		super();
		this.title = title;
		this.director = director;
		this.playingTime = playingTime;
		this.comment = comment;
	}

	//输出DVD信息
		public void print() {
			// TODO Auto-generated method stub
			System.out.println("DVD: " + title + "————" + director);
		}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
  • CD和DVD类的代码相似性高,Database中创建CD和DVD的代码大量重复,代码复制严重

改进:

Database

import java.util.ArrayList;

public class Database {
	
	//修改:
	private ArrayList<Item> listItem = new ArrayList<Item>();
	
	//添加CD信息
	public void add(Item item) {
		listItem.add(item);
	}
	
	//输出所有CD的信息
	public void list() {
		for(Item item : listItem) {
			item.print();
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Database db = new Database();
		db.add(new CD("从前有1首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new CD("从前有2首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new CD("从前有3首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new CD("从前有4首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!"));
		db.add(new DVD("我的**之旅", "霞基巴.卞德", 60, "好好看!"));
		db.list();
	}

}

父类Item

public class Item {

	// 不能用private,否则子类不能继承成员变量
	//方法一: protected: 自己、同一个包和子类能够访问
	protected String title;
	private int playingTime;//与子类CD中重复
	protected boolean gotIt = false;
	private String comment;
	


	public Item(int playingTime, String comment) {
		super();
		this.playingTime = playingTime;
		this.comment = comment;
	}

	//父类和子类中有相同的成员变量,在父类中操作时修改的是父类的该变量
	public void setPlayingTime(int playingTime) {
		this.playingTime = playingTime;
	}
	
	public void print() {
		System.out.println(comment);
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
	}

}

子类CD

public class CD extends Item{//CD extends CD扩展了Item,使CD成为Item的子类

	//如果父类和子类中有相同的成员变量,则父类的变量将会被隐藏
//	private String title;  //代码复制,将相同的成员变量放入父类Item    
	private String artist;
	private int numofTracks;
	private int playingTime;//与父类Item中重复
//	private boolean gotIt = false;
//	private String comment;
	
	//构造器
	public CD(String title, String artist, int numofTracks, int playingTime, String comment) {
		super(playingTime, comment);//根据super()的参数在父类中寻找对应的构造器,
		//父类的private变量仍然不能在子类中调用
		this.title = title;
		this.artist = artist;
		this.numofTracks = numofTracks;
		
		setPlayingTime(30);//这里修改的是父类中的playingTime
		
		this.playingTime = playingTime;
//		this.comment = comment;
	}
	
	
//	//输出CD信息
	public void print() { //如果CD没有print函数,则CD将继承Item的print函数
		// TODO Auto-generated method stub
		System.out.println("CD: " + title + "————" + artist);
		super.print(); //用super可以调用父类的print()
	}

	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		CD cd = new CD("从前有4首歌", "哲斯沃斯基.卞德", 4, 60, "好好听!");
		cd.print();
				
	}

}

子类DVD

public class DVD extends Item {//DVD是Item的子类

//	private String title;
	private String director;
//	private int playingTime;
//	private boolean gotIt = false;
//	private String comment;
	
	public DVD(String title, String director, int playingTime, String comment) {
		super(playingTime, comment);
		this.title = title;
		this.director = director;
//		this.playingTime = playingTime;
//		this.comment = comment;
	}

	//输出DVD信息
		public void print() {
			// TODO Auto-generated method stub
			System.out.println("DVD: " + title + "————" + director);
		}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
  1. 父类与子类的关系的确定:public class 子类 extends 父类 { }
  2. 子类和父类的联系:子类可以继承父类的变量和函数,但如果父类的变量设置访问属性为private,则子类无法访问
  3. 子类无法访问父类的private变量:
    方法一:
    设置父类变量的访问属性为protected:自己、同一个包和子类能够访问
    方法二:
    在父类中设置构造函数,在子类构造器的super()填入需要的变量,super()会根据super()的参数在父类中寻找对应的构造器完成变量的初始化,但是在子类中就无法操作父类的private变量(可以用super.父类的函数来间接操作在父类中的变量)
    (详见代码)
  4. 在父类和子类中有同名的变量,在子类函数中的变量就是子类自己的,在父类函数中的变量就是父类自己的,在哪里就操作哪里的变量

2. 子类

  1. 子类和子类型
    Alt

  1. 子类型与赋值
    ALt
  • 子类的对象都可以交给父类

  1. 子类和参数传递
    ALt

  1. 子类和容器
    ALt

3. 多态

  1. 多态变量
    Alt

  1. 造型Cast
  • 造型的正确用法
    ALt

  • 造型
    Alt

  • 向上造型:
    Alt


  1. 函数调用的绑定与覆盖override
  • 绑定
    Alt
    所以,在调用函数时,要看运行时实际管理的对象是谁来调用其的函数

  • 覆盖
    ALt
    所以,在操作 实际管理的类型是子类的时侯,子类的函数会将父类的同名同参函数覆盖

  • 因为上两者,所以在调用item.print()时,会调用子类的print()

  • [item在运行时的实际管理的类型是子类,所以函数绑定的是子类的print(),而子类的print()又会覆盖父类的print()]



4. Object类

  1. 所有类继承
    Alt
  • 所以所有类均能继承Object类的函数

  1. Object类的函数
    Alt

  1. 自动创建toString()——

Alt

  • 选中需要展示的变量后eclipse可自动创建

  1. 自动创建equals()——

Alt

  • 此方法需要手动修改:
    Alt

5. 增加新的子类

  1. 新的技巧——
  • 自动创建子类
    Alt

  • 自动创建继承自父类的构造器
    Alt


  1. 增加新的媒体类型
  • 不需要修改其它代码,直接扩展,能适应新的数据和内容——可扩展性
    Alt

  • 构建子类的子类,构成更深的继承关系,更有效的表达所有媒体类型
    Alt



二、城堡游戏

技巧:直接跳转到函数的声明处——

Alt

游戏操作:
	通过go、bye、help这三个简单的命令完成在城堡中的移动

1. 初步代码:

  1. Castle类:

    import java.util.Scanner;

    public class Castle {

    private Room currentRoom;
    
    public Castle() {
    	createRooms(); 
    }
    
    private void createRooms() {
    	Room outside, labby, pub, study, bedroom;
    	
    	//制造房间
    	outside = new Room("城堡外");
    	labby = new Room("大堂");
    	pub = new Room("小酒吧");
    	study = new Room("书房");
    	bedroom = new Room("卧室");
    	
    	//初始化房间的出口
    	outside.setExits(null, labby, study, pub);
    	labby.setExits(null, null, null, outside);
    	pub.setExits(null, outside, null, null);
    	study.setExits(outside, bedroom, null, null);
    	bedroom.setExits(null, null, null, study);
    	
    	currentRoom = outside;   //从城堡外开始
    	
    }
    
    private void printWelcome() {
    	System.out.println();
    	System.out.println("欢迎来到城堡!");
    	System.out.println("这是一个灰常有意思的游戏。");
    	System.out.println("如果需要帮助。请输入'help'。");
    	System.out.println();
    	
    	System.out.println("现在你在" + currentRoom);
    	System.out.println("出口有:");
    	if(currentRoom.northExit != null)
    		System.out.println("north ");
    	if(currentRoom.eastExit != null)
    		System.out.println("east ");
    	if(currentRoom.southExit != null)
    		System.out.println("south ");
    	if(currentRoom.westExit != null)
    		System.out.println("west ");
    	System.out.println();
    }
    
    //以下为用户命令
    private void printHelp() {
    	System.out.println("迷路了吗?你可以做的命令有:go bye help");
    	System.out.println("如:	go east");
    }
    
    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;
    	}
    	
    	if(nextRoom == null) {
    		System.out.println("那里没有门!");
    	}
    	else {
    		currentRoom = nextRoom;
    		
    		System.out.println("你在" + currentRoom);
    		System.out.println("出口有:");
    		if(currentRoom.northExit != null)
    			System.out.println("north");
    		if(currentRoom.eastExit != null)
    			System.out.println("east");
    		if(currentRoom.southExit != null)
    			System.out.println("south");
    		if(currentRoom.westExit != null)
    			System.out.println("west");
    		System.out.println();
    	}
    }
    
    public void showPrompt() {
    	System.out.println("现在你在" + currentRoom);
    	System.out.println("出口有:");
    	if(currentRoom.northExit != null)
    		System.out.println("north ");
    	if(currentRoom.eastExit != null)
    		System.out.println("east ");
    	if(currentRoom.southExit != null)
    		System.out.println("south ");
    	if(currentRoom.westExit != null)
    		System.out.println("west ");
    	System.out.println();
    }
    
    public static void main(String[] args) {
    	// TODO Auto-generated method stub
    	Scanner in = new Scanner(System.in);
    	Castle game = new Castle();
    	game.printWelcome();
    	
    	while(true) {
    		String line = in.nextLine();
    		String[] words = line.split(" ");
    		//split("a"):以a为分割,对字符串进行分割,将分割后的字符串分别装入数组返回字符串数组
    		if(words[0].toLowerCase().equals("help")) {
    			game.printHelp();
    		} 
    		else if(words[0].toLowerCase().equals("go")) {
    			game.goRoom(words[1]);
    		}
    		else if(words[0].toLowerCase().equals("bye")) {
    			break;
    		}
    	}
    	System.out.println("感谢您的光临,再见!");
    	in.close();
    }
    

    }


  1. Room类:

    public class Room {

    public String description;
    
    public Room northExit;
    public Room eastExit;
    public Room southExit;
    public Room westExit;
    
    public Room(String description) {
    	this.description = description;
    }
    
    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;
    }
    
    
    
    @Override
    public String toString() {
    	// TODO Auto-generated method stub
    	return description;
    }
    
    public static void main(String[] args) {
    	// TODO Auto-generated method stub
    
    }
    

    }


2. 改进一:消除代码复制

  1. 解决方法
    Alt

  1. 此段在Castle类中出现多次

    			System.out.println("你在" + currentRoom);
    			System.out.println("出口有:");
    			if(currentRoom.northExit != null)
    				System.out.println("north");
    			if(currentRoom.eastExit != null)
    				System.out.println("east");
    			if(currentRoom.southExit != null)
    				System.out.println("south");
    			if(currentRoom.westExit != null)
    				System.out.println("west");
    			System.out.println();
    
  • 改进:用函数封装

    	public void showPrompt() {
    		System.out.println("现在你在" + currentRoom);
    		System.out.println("出口有:");
    		if(currentRoom.northExit != null)
    			System.out.println("north ");
    		if(currentRoom.eastExit != null)
    			System.out.println("east ");
    		if(currentRoom.southExit != null)
    			System.out.println("south ");
    		if(currentRoom.westExit != null)
    			System.out.println("west ");
    		System.out.println();
    	}
    

3.改进二: 降低耦合

1.解决方法: 可扩展性
Alt
2. 方法1: 用封装来降低耦合
Alt

  • 耦合度低,类与类之间的关系不紧密,修改一个类对其它类的影响将会降低

  1. 问题一:

    public String description;
    
    public Room northExit;
    public Room eastExit;
    public Room southExit;
    public Room westExit;
    
  • 改进1: 将类的成员变量的访问属性修改成private

    private String description;
    
    private Room northExit;
    private Room eastExit;
    private Room southExit;
    private Room westExit;
    

  1. 问题二:

    		if(currentRoom.northExit != null)
    			System.out.println("north ");
    		if(currentRoom.eastExit != null)
    			System.out.println("east ");
    		if(currentRoom.southExit != null)
    			System.out.println("south ");
    		if(currentRoom.westExit != null)
    			System.out.println("west ");
    
  • 改进2:

    • 封装输出房间出口的函数

    • 放在Room类中,切断Castle类与Room类成员变量的连接

      public String getExitDesc() {
      StringBuffer sb = new StringBuffer();
      //String不可变,需要用Stringbuffer来拼接大量字符串
      if(northExit != null)
      sb.append("north ");
      // append()会添加新的字符串到原来的字符串上
      if(eastExit != null)
      sb.append("east ");
      if(southExit != null)
      sb.append("south ");
      if(westExit != null)
      sb.append("west ");
      return sb.toString();
      }

    • StringBuffer的作用:

    • 包括String在内的Wrapper类型都是是不可变类型,也就是这种类型的对象一旦创建好之后,再对其进行任何操作也不会改变其的属性和内容,只会再创建一个新的对象连接到旧对象的管理者上

    • 总之就是,在拼接字符串时,旧的字符串不会因为拼接了新的字符串而消失

    • 所以,如果需要用大量的小字符串拼接成一个长的字符串的时候,就会构造大量的中间的字符串,造成内存浪费

    • StringBuffer是可变的,当修改或者追加字符串到原来的对象上是,不会新生成一个字符串,而是在原来的对象上进行修改。这样,就不用分配大量的空间给中间的临时对象了。

具体可查看:Java之中StringBuffer的作用


  1. 问题三:

    		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;
    		}
    
  • 改进3:

    • 封装得出房间下一个出口的函数

    • 放在Room类中,切断Castle类与Room类成员变量的连接

      public Room getExit(String direction) {
      Room nextRoom = null;
      if(direction.equals(“north”)) {
      nextRoom = northExit;
      }
      if(direction.equals(“east”)) {
      nextRoom = eastExit;
      }
      if(direction.equals(“south”)) {
      nextRoom = southExit;
      }
      if(direction.equals(“west”)) {
      nextRoom = westExit;
      }
      return nextRoom;
      }


4.增加可扩展性

  1. 基础
    Alt
  • 给Room封装接口getExitDesc()和getExit()后,Room方向和房间的关系就不再收其它类的影响
  • 方便增加代码可扩展性

  1. 方法2:用容器来实现灵活性
    Alt

  1. 问题一:

    • 用成员变量表示Room方向,代码修改难度高

      private Room northExit;
      private Room eastExit;
      private Room southExit;
      private Room westExit;

  • 改进1:

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

  1. 问题二:修改Room类对应的函数
  • setExits(Room north, Room east, Room south, Room west):

    	public void setExit(String dir, Room room) {
    	exits.put(dir, room);
    }
    
  • public Room getExit(String direction)

    public Room getExit(String direction) {
    		return exits.get(direction);
    	}
    
  • public String getExitDesc()

    public String getExitDesc() {
    		StringBuffer sb = new StringBuffer();
    		//String不可变,需要用Stringbuffer来拼接大量字符串
    		for(String dir : exits.keySet()) {
    				sb.append(dir);
    				sb.append(' ');
    		}
    		return sb.toString();
    	}
    
  • creatRoom()中初始化房间出口的部分

    		outside.setExit("east", labby);
    		outside.setExit("south", study);
    		outside.setExit("west",  pub);
    		labby.setExit("west", outside);
    		pub.setExit("east", outside);
    		study.setExit("north", outside);
    		study.setExit("east", bedroom);
    		bedroom.setExit("west", study);
    			
    		//新增出口
    		pub.setExit("up", labby);
    		labby.setExit("down", pub);
    		
    		currentRoom = outside;   //从城堡外开始
    

  1. 方法3:以框架+数据来提高可扩展性
    Alt
  • 构建Handler父类及其子类HandlerGo、HandlerBye、HandlerHelp等方便扩展命令

  • Handler:

    public class Handler {
    protected Castle game;

    public Handler(Castle game) {
    	super();
    	this.game = game;
    }
    
    public void doCmd(String word) {
    	
    }
    
    public boolean isBye() {
    	return false;
    }
    

    }

  • HandlerBye:

    public class HandlerBye extends Handler {

    public HandlerBye(Castle game) {
    	super(game);
    	// TODO Auto-generated constructor stub
    }
    
    @Override
    public void doCmd(String word) {
    	
    }
    
    @Override
    public boolean isBye() {
    	// TODO Auto-generated method stub
    	return true;
    }
    

    }

  • HandlerHelp:

    public class HandlerHelp extends Handler {

    public HandlerHelp(Castle game) {
    	super(game);
    	// TODO Auto-generated constructor stub
    }
    
    @Override
    public void doCmd(String word) {
    	System.out.println("迷路了吗?你可以做的命令有:go bye help");
    	System.out.println("如:	go east");
    }
    

    }

  • HandlerGo:

    public class HandlerGo extends Handler {

    public HandlerGo(Castle game) {
    	super(game);
    	// TODO Auto-generated constructor stub
    }
    
    @Override
    public void doCmd(String word) {
    	// TODO Auto-generated method stub
    	game.goRoom(word);
    }
    

    }


  1. 问题三:修改对应的控制代码

    	while(true) {
    		String line = in.nextLine();
    		String[] words = line.split(" ");
    		//split("a"):以a为分割,对字符串进行分割,将分割后的字符串分别装入数组返回字符串数组
    		if(words[0].toLowerCase().equals("help")) {
    			game.printHelp();
    		} 
    		else if(words[0].toLowerCase().equals("go")) {
    			game.goRoom(words[1]);
    		}
    		else if(words[0].toLowerCase().equals("bye")) {
    			break;
    		}
    	}
    
  • 改进3:封装修正

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

    public void play() {
    Scanner in = new Scanner(System.in);
    while(true) {
    String line = in.nextLine();
    String[] words = line.split(" ");
    //split(“a”):以a为分割,对字符串进行分割,将分割后的字符串分别装入数组返回字符串数组

    		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;			
    			}
    	}
    	in.close();
    }
    

5. 修改后的代码

  1. Castle类:

    import java.util.HashMap;
    import java.util.Scanner;
    
    public class Castle {
    
    	private Room currentRoom;
    	
    	//改进:
    	private HashMap<String, Handler> handlers = new HashMap<String, Handler>();//命令
    	
    	public Castle() {
    		//改进:
    		//设置命令
    		handlers.put("go", new HandlerGo(this));
    		handlers.put("bye", new HandlerBye(this));
    		handlers.put("help", new HandlerHelp(this));
    		createRooms(); 
    	}
    	
    	private void createRooms() {
    		Room outside, labby, pub, study, bedroom;
    		
    		//制造房间
    		outside = new Room("城堡外");
    		labby = new Room("大堂");
    		pub = new Room("小酒吧");
    		study = new Room("书房");
    		bedroom = new Room("卧室");
    		
    		//改进:
    		//初始化房间的出口
    
    		outside.setExit("east", labby);
    		outside.setExit("south", study);
    		outside.setExit("west",  pub);
    		labby.setExit("west", outside);
    		pub.setExit("east", outside);
    		study.setExit("north", outside);
    		study.setExit("east", bedroom);
    		bedroom.setExit("west", study);
    		
    		//新增出口
    		pub.setExit("up", labby);
    		labby.setExit("down", pub);
    		
    		currentRoom = outside;   //从城堡外开始
    		
    	}
    
    
    	
    	private void printWelcome() {
    		System.out.println();
    		System.out.println("欢迎来到城堡!");
    		System.out.println("这是一个灰常有意思的游戏。");
    		System.out.println("如果需要帮助。请输入'help'。");
    		System.out.println();
    		
    		//改进:
    		showPrompt();
    	}
    	
    	//以下为用户命令
    	
    	//goRoom需要在Castle类里面完成,所以先用曲折的方法完成,
    	//更有效的方法将在后续学习中完成
    	public void goRoom(String direction) {
    
    		//改进:
    		Room nextRoom = currentRoom.getExit(direction);
    		if(nextRoom == null) {
    			System.out.println("那里没有门!");
    		}
    		else {
    			currentRoom = nextRoom;
    			
    			//改进:
    			showPrompt();
    		}
    	}
    	
    	public void showPrompt() {
    		System.out.println("现在你在" + currentRoom);
    		System.out.println("出口有:");
    		System.out.println(currentRoom.getExitDesc());
    		System.out.println();
    	}
    	
    	//改进:
    	public void play() {
    		Scanner in = new Scanner(System.in);
    		while(true) {
    			String line = in.nextLine();
    			String[] words = line.split(" ");
    			//split("a"):以a为分割,对字符串进行分割,将分割后的字符串分别装入数组返回字符串数组
    			
    			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;			
    				}
    		}
    		in.close();
    	}
    	
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Castle game = new Castle();
    		game.printWelcome();
    		game.play();
    
    		System.out.println("感谢您的光临,再见!");
    	}
    
    }
    

  1. Room类

    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() {
    	// TODO Auto-generated method stub
    	return description;
    }
    
    //改进:
    

    // 返回Room能通过的方向
    public String getExitDesc() {
    StringBuffer sb = new StringBuffer();
    //String不可变,需要用Stringbuffer来拼接大量字符串
    for(String dir : exits.keySet()) {
    sb.append(dir);
    sb.append(’ ');
    }
    return sb.toString();
    }

    public Room getExit(String direction) {
    	return exits.get(direction);
    }
    
    public static void main(String[] args) {
    	// TODO Auto-generated method stub
    
    	
    }
    

    }


  1. Handler父类

    public class Handler {
    protected Castle game;

    public Handler(Castle game) {
    	super();
    	this.game = game;
    }
    
    public void doCmd(String word) {
    	
    }
    
    public boolean isBye() {
    	return false;
    }
    

    }


  1. HandlerBye子类

    public class HandlerBye extends Handler {

    public HandlerBye(Castle game) {
    	super(game);
    	// TODO Auto-generated constructor stub
    }
    
    @Override
    public void doCmd(String word) {
    	
    }
    
    @Override
    public boolean isBye() {
    	// TODO Auto-generated method stub
    	return true;
    }
    

    }


  1. HandlerHelp子类

    public class HandlerHelp extends Handler {

    public HandlerHelp(Castle game) {
    	super(game);
    	// TODO Auto-generated constructor stub
    }
    
    @Override
    public void doCmd(String word) {
    	System.out.println("迷路了吗?你可以做的命令有:go bye help");
    	System.out.println("如:	go east");
    }
    

    }


  1. HandlerGo子类

    public class HandlerGo extends Handler {

    public HandlerGo(Castle game) {
    	super(game);
    	// TODO Auto-generated constructor stub
    }
    
    @Override
    public void doCmd(String word) {
    	// TODO Auto-generated method stub
    	game.goRoom(word);
    }
    

    }



三、抽象与接口

1. 抽象

  1. 抽象的作用
  • 抽象类是用来捕捉子类的通用特性的,是被用来创建继承层级里子类的模板。现实中有些父类中的方法确实没有必要写,因为各个子类中的这个方法肯定会有不同;而写成抽象类,这样看代码时,就知道这是抽象方法,而知道这个方法是在子类中实现的,所以有提示作用。
    Alt

理解抽象的用途:抽象的作用


  1. 抽象类与抽象函数
    Alt

  1. 实现抽象函数
    Alt

  1. 抽象的两种含义
    ALt

2. 细胞自动机——数据与表现分离

Alt

程序分析详见:细胞自动机

  1. 数据与表现分离
    Alt

  1. View和Field的关系

Alt


  1. 责任驱动的设计
    Alt

  1. 网格化

Alt

主要学习程序设计理念


3. 狐狸与兔子

Alr

程序分析详见:狐狸与兔子

  1. 接口
    Alt

  1. 实现接口
    Alt

Alt


  1. 面向接口的编程方式

Alt

不理解接口,看个Java 接口 | 菜鸟教程


4.抽象类和接口

一般需要实现多重继承时,可以使用接口

  1. 共同点
  • 都不能被实例化,可以被继承或实现
  • 都可以包含抽象函数
  1. 不同点
  • 接口中的函数必须为抽象函数,抽象类中可以有普通函数(接口中的普通方法默认为抽象方法)
  • 接口的成员变量必须加public static fianl,且必须赋值
  • 接口不能有构造器、不能初始化,抽象类可以
  • 一个类只能继承一个抽象类,但是可以实现多个接口

详情见Java接口与抽象类的区别


  1. JDK1.8:
  • 用default修饰实现非抽象的方法
  • 用static修饰实现接口静态方法

详情见Java接口与抽象类的区别


  1. java类的继承、抽象类与接口的区别

java类的继承、抽象类与接口的区别


  1. 控制反转

控制反转(IoC)与依赖注入(DI)


5. 内部类和匿名类

  1. 内部类

在一个类内部的类:
Alt

Alt


  1. 匿名类

Alt
Alt



四、总结

1. 类的关系

  1. 子类型
    Alt

  1. 多态
    Alt

  1. 函数调用的绑定和覆盖override

Alt


  1. Object类
    Alt

  1. 增加新的子类
    Alt

2. 城堡游戏:代码的优化

Alt
Alt


3. 抽象与接口

  1. 抽象
    Alt

  1. 细胞自动机——数据与表现分离
    Alt

  1. 狐狸和兔子——实现接口

Alt


  1. 内部类和匿名类
    Alt
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值