在第一章就有一个Shape类的例子。这个类有很多的子类,每个子类也都实现了父类的方法。实际上父类Shape只是一个抽象的概念而并没有实际的意义。如果请你画一个圆,你知道该怎么画;如果请你画一个矩形,你也知道该怎么画。但是如果我说:“请画一个形状,句号”。你该怎么画?同样,我们可以定义Circle类和Rectangle类的draw(),但是Shape类的draw()呢?
Shape类表达的是一种概念,一种共同属性的抽象集合,我们并不希望任何Shape类的对象会被创建出来。那么,我们就应该把这个Shape类定义为抽象的。我们用abstract关键字来定义抽象类。抽象类的作用仅仅是表达接口,而不是具体的实现细节。抽象类中可以存在抽象方法。抽象方法也是使用abstract关键字来修饰。抽象的方法是不完全的,它只是一个方法签名而完全没有方法体。
如果一个类有了一个抽象的方法,这个类就必须声明为抽象类。如果父类是抽象类,那么子类必须覆盖所有在父类中的抽象方法,否则子类也成为一个抽象类。一个抽象类可以没有任何抽象方法,所有的方法都有方法体,但是整个类是抽象的。设计这样的抽象类主要是为了防止制造它的对象出来。
在shape例子里有abstract的类及方法如下:
public abstract class Shape {
public abstract void draw(Graphics g);
}
shape没有存在的意义只是表达一种概念,draw方法也没有存在意义。
实现抽象方法:
两种抽象:
与具体相对:表示一种概念而非实体
与细节相对:表示在一定程度上忽略细节而着眼大局
细胞自动机:
cellmachine:
package cellmachine;
import javax.swing.JFrame;
import cell.Cell;
import field.Field;
import field.View;
public class CellMachine {
public static void main(String[] args) {
//30*30的网格
Field field = new Field(30,30);
//在每个网格中放置cell对象
for ( int row = 0; row");
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();
}
}
}
}
view:
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
Data:Field/Cell
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 list = new ArrayList();
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-1 && c | |
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);
}
}
}
责任驱动设计:将程序要实现的功能分配到合适的类/对象中去是设计中非常重要的一环
网格化:
问题:
1、为什么不是在cell提供setAlive(Boolean)函数?而是采用复杂的die()、reborn()两个函数?
2、为什么filed.getNeighbour()不直接看cell.isAlive()来返回一个数字,而是要返回一个数组让外面来数数?
3、为什么不是cell自己判断自己的邻居的情况来决定自己是否应该die或reborn?
狐狸和兔子都有年龄
当年龄到了一定的上线就会自然死亡
狐狸可以随机决定在周围的兔子中吃一个
狐狸哥兔子可以随机决定吃一个小的,放在旁边的空的格子里
如果不吃也不生,狐狸和兔子可以随机决定向旁边空的格子移一步
cell类的地位很尴尬:
从图中可得rabbit继承animal类和cell类,这是一种多继承,大多数的oop语言都不支持多继承(除c++外),因为多继承在实现上不好实现。
若animal类与cell类相关联从语义上是不可行的,动物类和格子并没有确定的关系。但filed还需一个他认识的东西进行管理。
接口:
所以将cell定义为接口,fox和rabbit实现cell的接口。使用关键词implements
因为cell是接口所以他不可能有对象,o的意思是任何实现了cell接口的对象(fox/rabbit)
实现接口:
面对接口的编程方式:
Cell和Field的关系:cell在field中,但是cell的很多操作需要field的数据。方法一:让每个cell有一个filed的管理者(cell知道field)。方法二:有外部第三方来建立两者之间的联系(cell不知道filed)。
讨论: