以下为个人学习笔记和习题整理
课程:面向对象程序设计 ——Java 语言
- 浙江大学 - 翁恺 @ 中国大学 MOOC
https://www.icourse163.org/course/ZJU-1001542001

# 课堂笔记

# 抽象 abstract

抽象函数:表达概念而无法实现具体代码的函数。
抽象类:表达概念而无法构造出实体的类。

用 abstract 关键字来定义抽象类。

抽象类的作用仅仅是表达接口,而不是具体的实现细节。

抽象类中可以存在抽象方法。
抽象方法也是使用 abstract 关键字来修饰。
抽象的方法是不完全的,它只是一个方法签名而完全没有方法体,不能带 {} 。

如果一个类有了一个抽象的方法,这个类就必须声明为抽象类。

有抽象函数的类,一定是抽象类。

一个抽象类可以没有任何抽象方法,所有的方法都有方法体,但是整个类是抽象的。
设计这样的抽象类主要是为了防止制造它的对象出来。
任何继承类抽象类的非抽象类的对象,可以赋给这个变量。

抽象类不能制造对象,但是可以定义变量。

如果父类是抽象类,那么子类必须覆盖所有在父类中的抽象方法,否则子类也成为一个抽象类。

# 两种抽象

  • 与具体相对:表示一种概念而非实体
  • 与细节相对:表示在一定程度上忽略细节而着眼大局

# 接口 interface

接口是纯抽象类

  • 所有的成员函数都是抽象函数
  • 所有的成员变量都是 public static final

接口规定了长什么样,但是不管里面有什么。

interface 是一种特殊的 class ,使用时取代 class 的位置。

# 实现接口 implements

类用 extends ,接口用 implements
类可以实现很多接口
接口可以继承接口,但不能继承类
接口不能实现接口

# 面向接口的编程方式

设计程序时先定义接口,再实现类。
任何需要在函数间传入传出的一定是接口,而不是具体的类。
是 Java 成功的关键之一,因为极适合多人同时写一个大程序。
也是 Java 被批评的要点之一,因为代码量膨胀起来很快。

# 课内代码

# 细胞自动机

死亡:如果活着的邻居的数量<2 或>3,则死亡
新生:如果正好有 3 个邻居活着,则新生
其他情况则保持原状

package cellmachine;
import javax.swing.JFrame;
import cell.Cell;
import field.Field;
import field.View;
public class CellMachine {
	public static void main(String[] args) {
		Field field = new Field(30,30);
		for ( int row = 0; row<field.getHeight(); row++ ) {
			for ( int col = 0; col<field.getWidth(); col++ ) {
				field.place(row, col, new Cell());
			}
		}
		for ( int row = 0; row<field.getHeight(); row++ ) {
			for ( int col = 0; col<field.getWidth(); col++ ) {
				Cell cell = field.get(row, col);
				if ( Math.random() < 0.2 ) {
					cell.reborn();
				}
			}
		}
		View view = new View(field);
		JFrame frame = new JFrame();// 图形窗口
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 默认关闭的操作
		frame.setResizable(false);
		frame.setTitle("Cells");
		frame.add(view);
		frame.pack();
		frame.setVisible(true);
		
		for ( int i=0; i<1000; i++ ) {
			for ( int row = 0; row<field.getHeight(); row++ ) {
				for ( int col = 0; col<field.getWidth(); col++ ) {
					Cell cell = field.get(row, col);
					Cell[] neighbour = field.getNeighbour(row, col);
					int numOfLive = 0;
					for ( Cell c : neighbour ) {
						if ( c.isAlive() ) {
							numOfLive++;
						}
					}
					System.out.print("["+row+"]["+col+"]:");
					System.out.print(cell.isAlive()?"live":"dead");
					System.out.print(":"+numOfLive+"-->");
					if ( cell.isAlive() ) {
						if ( numOfLive <2 || numOfLive >3 ) {
							cell.die();
							System.out.print("die");
						}
					} else if ( numOfLive == 3 ) {
						cell.reborn();
						System.out.print("reborn");
					}
					System.out.println();
				}
			}
			System.out.println("UPDATE");
			frame.repaint();
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
package cell;
import java.awt.Graphics;
 
public class Cell {
	private boolean alive = false;
	
	public void die() { alive = false; }
	public void reborn() { alive = true; }
	public boolean isAlive() { return alive; }
	
	public void draw(Graphics g, int x, int y, int size) {
		g.drawRect(x, y, size, size);
		if ( alive ) {
			g.fillRect(x, y, size, size);
		}
	}
}
package field;
import java.util.ArrayList;
import cell.Cell;
public class Field {
	private int width;
	private int height;
	private Cell[][] field;
	
	public Field(int width, int height) {
		this.width = width;
		this.height = height;
		field = new Cell[height][width];
	}
	
	public int getWidth() { return width; }
	public int getHeight() { return height; }
	
	public Cell place(int row, int col, Cell o) {
		Cell ret = field[row][col];
		field[row][col] = o;
		return ret;
	}
	
	public Cell get(int row, int col) {
		return field[row][col];
	}
	
	public Cell[] getNeighbour(int row, int col) {
		ArrayList<Cell> list = new ArrayList<Cell>();
		for ( int i=-1; i<2; i++ ) {
			for ( int j=-1; j<2; j++ ) {
				int r = row+i;
				int c = col+j;
				if ( r >-1 && r<height && c>-1 && c<width && !(r== row && c == col) ) {
					list.add(field[r][c]);
				}
			}
		}
		return list.toArray(new Cell[list.size()]);
	}
	
	public void clear() {
		for ( int i=0; i<height; i++ ) {
			for ( int j=0; j<width; j++ ) {
				field[i][j] = null;
			}
		}
	}
}
package field;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import cell.Cell;
public class View extends JPanel {
	private static final long serialVersionUID = -5258995676212660595L;
	private static final int GRID_SIZE = 16;
	private Field theField;
	
	public View(Field field) {
		theField = field;
	}
	@Override
	public void paint(Graphics g) {
		super.paint(g);
		for ( int row = 0; row<theField.getHeight(); row++ ) {
			for ( int col = 0; col<theField.getWidth(); col++ ) {
				Cell cell = theField.get(row, col);
				if ( cell != null ) {
					cell.draw(g, col*GRID_SIZE, row*GRID_SIZE, GRID_SIZE);
				}
			}
		}
	}
	@Override
	public Dimension getPreferredSize() {
		return new Dimension(theField.getWidth()*GRID_SIZE+1, theField.getHeight()*GRID_SIZE+1);
	}
	public static void main(String[] args) {
		Field field = new Field(10,10);
		for ( int row = 0; row<field.getHeight(); row++ ) {
			for ( int col = 0; col<field.getWidth(); col++ ) {
				field.place(row, col, new Cell());
			}
		}
		View view = new View(field);
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setResizable(false);
		frame.setTitle("Cells");
		frame.add(view);
		frame.pack();
		frame.setVisible(true);
	}
}

# 设计理念

  1. 数据与表现分离
    程序的业务逻辑与表现无关
    表现可以是图形的也可以是文本的
    表现可以是当地的也可以是远程的

表现与数据的关系
View 只管根据 Field 画出图形, Field 只管数据的存放。
一旦数据更新以后,通知 View 重新画出整个画面,不去精心设计哪个局部需要更新,这样简化了程序逻辑,是在计算机运算速度提高的基础上实现的。

  1. 责任驱动的设计
    将程序要实现的功能分配到合适的类 / 对象中去是设计中非常中要的一环

  2. 网格化
    图形界面本身有更高的解析度
    但是将画面网格化以后,数据就更容易处理了

# 狐狸与兔子

狐狸、兔子都有年龄;
到达一定年龄上限会自然死亡;
狐狸随机吃掉周围一只兔子;
狐狸、兔子可以随机生一只小的放在旁边格子;
如果不吃不生,狐狸、兔子可以随机向旁边格子移一步会随机吃掉。

# FoxAndRabbit 程序执行入口

主要思想:
两层 for 循环,挨个 cell 执行移动、进食、生育;
每次循环结束后 repaint view 。

package FoxAndRabbit;
import field.Field;
import field.View;
import field.Location;
import java.util.ArrayList;
import javax.swing.JFrame;
import animal.Fox;
import animal.Rabbit;
import animal.Animal;
import cell.Cell;
public class FoxAndRabbit{
	private Field thefield;
	private View theview;
	
	public FoxAndRabbit( int size ){
		thefield = new Field(size, size);
		for( int row = 0; row <thefield.getHeight(); row++ ){
			for( int col = 0; col < thefield.getWidth(); col++ ){
				double probability = Math.random();
				if( probability <0.05 ){
					thefield.place( row, col, new Fox());
				}else if( probability < 0.15 ){
					thefield.place( row, col, new Rabbit());
				}
			}
		}
		theview = new View(thefield);
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setResizable(false);
		frame.setTitle("FoxAndRabbit");
		frame.add(theview);
		frame.pack();
		frame.setVisible(true);
	}
	
	public void step(){
		for( int row = 0; row < thefield.getHeight(); row++ ){
			for( int col = 0; col < thefield.getWidth(); col++ ){
				Cell cell = thefield.get(row, col);
				if( cell != null ){
					Animal animal = (Animal)cell;
					animal.grow();
					if( animal.isAlive()){
						//move
						Location loc = animal.move(thefield.getFreeNeighbour(row, col));
						if( loc != null ){
							thefield.move(row, col, loc);
						}
						//eat   animal.eat(thefield);
						if( animal instanceof Fox){
							Cell[] neighbour = thefield.getNeighbour(row, col);
							ArrayList<Animal> listRabbit = new ArrayList<Animal>();
							for( Cell an : neighbour ){
								if( an instanceof Rabbit ){
									listRabbit.add( (Rabbit)an );
								}
							}
							if( !listRabbit.isEmpty() ){
								Animal fed = animal.feed(listRabbit);
								if( fed != null ){
									thefield.remove((Cell)fed);
								}
							}
						}
						//breed
						Animal baby = animal.breed();
						if( baby != null ){
							thefield.placeRandomAdj(row, col, (Cell)baby);
						}
					}else{
						thefield.remove(row, col);
					}
				}
			}
		}	
	}
	
	public void start( int steps ){
		for( int i = 0; i < steps; i++){
			step();
			theview.repaint();
			try{
				Thread.sleep(200);
			}catch (InterruptedException e){
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		FoxAndRabbit fnr = new FoxAndRabbit(30);
		fnr.start(10);
	}
}

# cell 包

# Cell 接口类

package cell;
import java.awt.Graphics;
 
public interface Cell {	
	void draw(Graphics g, int x, int y, int size);
}

# field 包

# Location 类

用于定位,返回所要 cell 位置。

package field;
public class Location{
	private int row;
	private int col;
	
	public Location( int row, int col ){
		this.col = col;
		this.row = row;
	}
	
	public int getRow(){
		return row;
	}
	public int getCol() {
		return col;
	}
}

# Field 类

package field;
import java.util.ArrayList;
import cell.Cell;
public class Field {
//  这段代码没用到过
//	private static final Location[] adjacent = {
//			new Location(-1,-1),new Location(-1,0),new Location(-1,1),
//			new Location(0,-1) ,new Location(0,0) ,new Location(0,-1), 
//			new Location(1,-1) ,new Location(1,-1),new Location(1,-1),
//	};
	private int width; // 长
	private int height; // 宽
	private Cell[][] field; //cell 二维数组
	
	/**
	 * 构造方法:生成指定大小 cell 二维数组
	 * @param  width  长
	 * @param  height 宽
	 */
	public Field(int width, int height){
		this.height = height;
		this.width = width;
		field = new Cell[height][width];
	}
	
	/**
	 * 简单方法:获取长、宽、指定 cell
	 * @return [description]
	 */
	public int getWidth(){ return width; }
	public int getHeight(){ return height; }
	
	public Cell get(int row, int col){
		return field[row][col];
	}
	
	/**
	 * 获取周围 cell
	 * @param  row 当前 cell 的坐标:行
	 * @param  col 当前 cell 的坐标:列
	 * @return     周围 cell 数组
	 */
	public Cell[] getNeighbour(int row, int col) {
		ArrayList<Cell> list = new ArrayList<Cell>();
		for( int i = -1; i<2; i++ ) {
			for( int j = -1; j<2; j++ ) {
				int r = row+i;
				int c = col+j;
				if( r>-1 && r<height && c>-1 && c<width && !(r == row && c == col)) {
					list.add(field[r][c]);
				}
			}
		}
		return list.toArray(new Cell[list.size()]);
	}
	
	/**
	 * 列出周围的空 cell
	 * @param  row 当前 cell 的坐标:行
	 * @param  col 当前 cell 的坐标:列
	 * @return     周围的空 cell 数组
	 */
	public Location[] getFreeNeighbour(int row, int col) {   
		ArrayList<Location> list = new ArrayList<Location>();
		for( int i = -1; i<2; i++ ) {
			for( int j = -1; j<2; j++ ) {
				int r = row+i;
				int c = col+j;
				if( r>-1 && r<height && c>-1 && c<width && field[r][c] == null ) {
					list.add(new Location(r, c));
				}
			}
		}
		return list.toArray(new Location[list.size()]);
	}
	
	/**
	 * 在周围空 cell 里放置一个 cell
	 * @param  row  当前 cell 的坐标:行
	 * @param  col  当前 cell 的坐标:列
	 * @param  cell 待放入的 cell
	 * @return      是否成功放入 cell 进 field
	 */
	public boolean placeRandomAdj( int row, int col, Cell cell ){   
		boolean ret = false;
		Location[] FreeAdj = getFreeNeighbour(row, col);
		if( FreeAdj.length > 0 ){
			int idx = (int)(Math.random()*FreeAdj.length);
			field[FreeAdj[idx].getRow()][FreeAdj[idx].getCol()] = cell;
			ret = true;
		}
		return ret;
	}
	
	/**
	 * 根据坐标删除 cell
	 * @param  row 待删除 cell 的坐标:行
	 * @param  col 待删除 cell 的坐标:列
	 * @return     
	 */
	public Cell remove( int row, int col ){
		Cell ret = field[row][col];
		field[row][col] = null;
		return ret;
	}
	
	/**
	 * 删除 cell
	 * @param cell 待删除的 cell
	 */
	public void remove( Cell cell ){
		for( int row = 0; row < height; row++ ){
			for( int col = 0; col <width; col++ ){
				if( field[row][col] == cell ){
					field[row][col] = null;
					break;
				}
			}
		}
	}
	
	/**
	 * 清空所有 cell
	 */
	public void clear(){
		for( int i = 0; i < height; i++){
			for( int j = 0; j < width; j++){
				field[i][j] = null;
			}
		}
	}
	
	/**
	 * 移动 cell
	 * @param row 当前 cell 的坐标:行
	 * @param col 当前 cell 的坐标:列
	 * @param loc 目标坐标的 Location
	 */
	public void move(int row, int col, Location loc){
		field[loc.getRow()][loc.getCol()] = field[row][col];
		remove(row,col);
	}
	public Cell place(int row, int col, Cell c) {
		Cell ret = field[row][col];
		field[row][col] = c;
		return ret;
	}
}

# View 类

继承自 JPanel 面板
重写的方法: paint ,设置刚好的尺寸。

package field;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
import cell.Cell;
public class View extends JPanel{
	private static final long serialVersionUID = -2417015700213488315L;
	private static final int GRID_SIZE = 16;
	private Field thefield;
	
	public View (Field field){
		thefield = field;
	}
	
	@Override
	public void paint( Graphics g ){
		super.paint(g);
		g.setColor(Color.gray);
		for( int row = 0; row < thefield.getHeight(); row++ ){
			g.drawLine(0, row*GRID_SIZE, thefield.getWidth()*GRID_SIZE, row*GRID_SIZE);
		}
		for( int col = 0; col < thefield.getHeight(); col++ ){
			g.drawLine(col*GRID_SIZE, 0, col*GRID_SIZE, thefield.getHeight()*GRID_SIZE);
		}
		for( int row = 0; row < thefield.getHeight(); row++){
			for( int col = 0; col < thefield.getWidth(); col++){
				Cell cell = thefield.get(row, col);
				if( cell != null ){
					cell.draw( g, col*GRID_SIZE, row*GRID_SIZE, GRID_SIZE);
				}
			}
		}
	}
	
	@Override
	public Dimension getPreferredSize(){
		return new Dimension(thefield.getWidth()*GRID_SIZE+1, thefield.getHeight()*GRID_SIZE+1);
	}
}

# animal 包

# Animal 抽象类

是 fox , rabbit 的父类。

package animal;
import java.util.ArrayList;
import field.Location;
public abstract class Animal
{
	private int ageLimit; // 生存时间
	private int breedableAge; // 生育年龄
	private int age; // 现年龄
	private boolean isAlive = true; // 是否存活
	
	/**
	 * 构造方法
	 * @param  ageLimit     生存时间
	 * @param  breedableAge 生育年龄
	 */
	public Animal(int ageLimit, int breedableAge){
		this.ageLimit = ageLimit;
		this.breedableAge = breedableAge;
	}
	
	/**
	 * 简单方法:获取年龄
	 * @return 现年龄
	 */
	protected int getAge(){
		return age;
	}
	
	/**
	 * 简单方法:获取年龄百分比
	 * @return 年龄百分比
	 */
	protected double getAgePercent(){
		return (double)age/ageLimit;
	}	
	
	/**
	 * 简单方法:存活状态
	 * @return 是否存活
	 */
	public boolean isAlive(){
		return isAlive;
	}
	
	/**
	 * 简单方法:生育状态
	 * @return 是否能够生育
	 */
	public boolean isBreedable(){
		return age > breedableAge;
	}	
	
	/**
	 * 简单方法:寿命增长
	 * @param addage 增长数值
	 */
	protected void longerlife( int addage ){
		ageLimit += addage;
	}
	/**
	 * 简单方法:成长(到年龄死亡)
	 */
	public void grow(){
		age++;
		if(age > ageLimit){
			die();
		}
	}
	/**
	 * 简单方法:死亡
	 */
	private void die() {
		isAlive = false;
	}
	
	/**
	 * 移动方法
	 * @param  freeAdj 周围空 cell 坐标
	 * @return         其中一个空 cell 坐标
	 */
	public Location move(Location[] freeAdj){
		Location ret = null;
		if( freeAdj.length > 0 && Math.random() < 0.02 ){
			ret = freeAdj[(int)(Math.random()*freeAdj.length)];
		}
		return ret;
	}
	
	/**
	 * 抽象方法:生育
	 */
	public abstract Animal breed();
	/**
	 * 返回值方法:进食
	 * @param  neighbour 附近动物的数组
	 * @return 被吃的动物          
	 */
	public Animal feed(ArrayList<Animal> neighbour){
		return null;
	}
	
	@Override
	public String toString(){
		return " "+age+":"+(isAlive?"live":"dead");
	}
}

# Fox 类

继承 Animal , Cell

package animal;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import cell.Cell;
public class Fox extends Animal implements Cell
{
	/**
	 * 构造方法
	 * 生存时间 20,生育年龄 4
	 */
	public Fox(){
		super(20,4);     // 最大年龄,生育年龄
	}
	
	/**
	 * 重写接口 cell 方法:draw
	 * @param g    cell 图
	 * @param x    x 坐标
	 * @param y    y 坐标
	 * @param size 大小
	 */
	@Override
	public void draw( Graphics g, int x, int y, int size ){
		int alpha = (int)((1-getAgePercent())*255);
		g.setColor(new Color(0,0,0,alpha));
		g.fillRect(x, y, size, size);
	}
	
	/**
	 * 重写抽象方法:Animal 的生育
	 * @return Animal
	 */
	@Override
	public Animal breed() {
		Animal ret = null;
		// 生育的概率是 5%
		if( isBreedable() && Math.random() < 0.05 ){   
			ret = new Fox();
		}
		return ret;
	}
	
	/**
	 * 重写方法:Animal 的进食
	 * @param  neighbour 附近兔子的数组
	 * @return           被吃的兔子
	 */
	@Override
	public Animal feed(ArrayList<Animal> neighbour){
		Animal ret = null;
		// 被吃的概率为 20%
		if( Math.random() < 0.2 ){
			ret = neighbour.get((int)(Math.random()*neighbour.size()));
			longerlife(2);
		}
		return ret;
	}
	
	@Override
	public String toString(){
		return "Fox:"+super.toString();
	}
}

# Rabbit 类

继承 Animal , Cell

package animal;
import java.awt.Color;
import java.awt.Graphics;
import cell.Cell;
public class Rabbit extends Animal implements Cell
{
	/**
	 * 构造方法
	 * 生存时间 10,生育年龄 2
	 */
	public Rabbit() {
		super(10, 2);
	}
	/**
	 * 重写接口 cell 方法:draw
	 * @param g    cell 图
	 * @param x    x 坐标
	 * @param y    y 坐标
	 * @param size 大小
	 */
	@Override
	public void draw(Graphics g, int x, int y, int size) {
		int alpha = (int)((1-getAgePercent())*255);
		g.setColor(new Color(255,0,0,alpha));
		g.fillRect(x, y, size, size);
	}
	/**
	 * 重写抽象方法:Animal 的生育
	 * @return Animal
	 */
	@Override
	public Animal breed() {
		Animal ret = null;
		// 生育的概率是 12%
		if( isBreedable() && Math.random() < 0.12 ){
			ret = new Rabbit();
		}
		return ret;
	}
	
	@Override
	public String toString(){
		return "Rabbit:"+super.toString();
	}
}

# 课堂讨论

# 细胞自动机

  1. 为什么没有 Cell.setAlive() ?为什么不是在 Cell 提供 setAlive(boolean) 函数?而是采用复杂的 die() 、 reborn() 两个函数?

提高可阅读性,且 Cellmachine 类就是用来实现人机交互,业务逻辑交给 Cell 类。

  1. 为什么 Field.getNeighbour() 不直接看 Cell.isAlive() 来返回一个数字,而是要返回一个数组让外面来数数?

Field 这个类的职责是为对象提供一个可定位的安放空间,它不需要知道对象的任何额外信息。这种低耦合设计使得 Cell 变动时 Field 无须作出调整。

  1. 为什么不是由 Cell 自己判断自己的邻居的情况来决定自己是否应该被 die 或 reborn ?

Cell 要知道自己被生还是被死,就要获取一个数组, Cell 类, Cellmachine 类, Field 类就会相互使用,面向设计原则有一点是单一原则,各类各司其职,判断细胞是生是死让 Cellmachine 做就行了, Cell 只要负责提供细胞就行了。
好处就是简化了 Cellmachine 的代码,增加可读性,降低复杂性。

# 狐狸与兔子

  1. Fox.breed() 和 Rabbit.breed() 几乎一样,有什么好办法修改?注意 Fox 和 Rabbit 的 breed() 返回的具体类型不同。

Animal 中定义

protected double breedPercent;
public abstract Animal newAnimal();
public Animal breed() {
	Animal ret = null;
	if ( isBreedable() &&  Math.random()< breedPercent) {
		return newAnimal();
    }
	return ret;
}

Fox 中定义

protected double breedPercent = 0.05;
@Override
public Animal newAnimal() {
    return new Fox();
}

Rabbit 中定义

protected double breedPercent = 0.12;
@Override
public Animal newAnimal() {
    return new Rabbit();
}
  1. 在城堡游戏中, Handler 是知道 Game 的;在细胞自动机中, Cell 是不知道 Field 的。在现在版本的狐狸与兔子中, Cell 也是不知道 Field 的。那么,如果让 Cell 知道 Field 会怎样呢?两种做法各有什么优缺点呢?

Cell 不知道 Field 的话, Cell 比较独立,对 Field 的修改不会影响到 Cell , Cell 也可以单独拿到其他地方用。
如果 Cell 和 Field 之间有重复的复杂的交互的话,可以把交互过程放到一个方法里;如果这种交互的主体是 Cell 的话,那么把交互方法放入 Cell 就有一定合理性,这类交互越多, Cell 知道 Field 的好处就越多。其中就是独立和便捷之间的权衡。

  1. 如果另外用一个 ArrayList<Animal> 来表示所有的动物,每一步遍历这个列表而非整个 Field ,这样做是否更好?
    提示:这样就需要每个 Animal 知道自己在 Field 里的位置。

Animal 知道位置的话对 Field 就有了依赖。
死亡时需要查找和删除动物,使用 ArrayList 效率不高,用 HashMap 好些。
在动物出生和移动时,需要同时设置 Field 和 Animal 中的数据。

  1. 现在 Cell 接口其实是承担了两个责任的。在 Field 看过来,它只认识 Cell ,它认为 Cell 是存放在其中的数据。而对于 View 来说,它看到的是 Cell 所具有的 draw 方法,从这个角度来说 Cell 表示了表现。
    有没有必要两种分开。比如有一个 Cell 抽象类表示可以放进 Field 的东西,另一个 Drawable 接口表示可以被 View 画出来的东西?
阅读次数 次

请我喝[茶]~( ̄▽ ̄)~*

Ruri Shimotsuki 微信支付

微信支付

Ruri Shimotsuki 支付宝

支付宝

Ruri Shimotsuki 贝宝

贝宝