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("如:\tgo 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("如:\tgo 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("如:\tgo 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
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值