Java进阶学习笔记(十)

1、数据与表现分离--细胞自动机:

  • 死亡:如果活着的邻居的数量<2或>3,则死亡;
  • 新生:如果正好有3个邻居活着,则新生;
  • 其他情况则保持原状;
package cellmachine;
import java.lang.reflect.Field;

import javax.swing.JFrame;

public class Cellmachine {

    public static void main(String[] args) {
        Field field = new Field(30,30);//30x30的网格
        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();*
            }
        }
    }
}

1.1 数据与表现分离:

  • 程序的业务逻辑与表现无关;
    • 表现可以是图形的也可以是文本的;
    • 表现可以是当地的也可以是远程的;

1.2 View和Field的关系:

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

public class View extends JPanel {//图形库画面
    private static final long serialVersionUID = -52589956212330595L;
    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

1.3 责任驱动的设计:

  • 将程序要实现的功能分配到合适的类/对象中去是设计中非常重要的一环;

1.4 网格化:

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

1.5 问题0:

  • 为什么不是在Cell提供setAlive(boolean)函数,而是采用复杂的die()、reborn()函数?
package cells;

import java.awt.Graphics;

public class Cell {
    private boolean alive = false;
    
    public void die() {alive = false;}
    public void reborn() {alive = false;}
    public boolean isAlive() {return alive;}
    
    public void draw(Graphics g,int x,int y,int size) {
        if(alive) {
            g.fillRect(x,y,size,size);
        }
    }
}

1.6 问题1:

  • 为什么Field.getNeighbor()不直接看Cell.isAlive()来返回一个数字,而是要返回一个数组让外面来数数?
public Cell[]getNeighbour(int row,int col){
        ArrayListlist = 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

1.7 问题2:

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

import java.awt.Graphics;

public class Cell {
    private boolean alive = false;
    
    public void die() {alive = false;}
    public void reborn() {alive = false;}
    public boolean isAlive() {return alive;}
    
    public void draw(Graphics g,int x,int y,int size) {
        if(alive) {
            g.fillRect(x,y,size,size);
        }
    }

}

2、接口--狐狸与兔子:

2.1 狐狸与兔子:

  • 狐狸与兔子都有年龄;
  • 当年龄到了一定的上限就会自然死亡;
  • 狐狸可以随机决定在周围的兔子中吃一个;
  • 狐狸和兔子可以随机决定生一个小的,放在旁边的空的格子里;
  • 如果不吃也不生,狐狸和兔子可以随机决定向旁边空的格子移一步;
package foxnrabbit;
import java.util.ArrayList;
import javax.swing.JFrame;

public class FoxnrAndabbit {
    private Field theField;
    private View theView;
    
    public FoxnrAndrabbit(int size) {
        for(int row=0;row

2.2 Cell类的地位很尴尬:

  • 在Cells程序中它表达了细胞;
  • 但是同时它也表达了放在网格中的一个格子‘
  • Fox和Rabbit是否应该从Cell继承?


    image.png

2.3 接口(表达概念、规范):

  • 接口是纯抽象类;
    • 所有的成员函数都是抽象函数;
    • 所有的成员变量都是public static final;
  • 接口规定了长什么样,但是不管里面有什么;


    image.png
package field;

import java.util.ArrayList;

public class Field {
    private static final Location[] adjacent = {
            new Locaton(-1-1),new Location(-1,0),new Location(-1,-1),
            new Locaton(0,-1),new Location(0,0),new Location(0,1),
            new Locaton(1-1),new Location(1,0),new Location(1,1),
    };
    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 gerHeight() {return height;}
    
    public Cell place(int row,int col,Cell o) {//o表示任何实现了Cell接口的对象
        return field[row][col];
    }

2.4 主程序:

package foxnrabbit;

import java.util.ArrayList;

import javax.swing.JFrame;

import field.Field;

public class FoxnrAndabbit {
    private Field theField;
    private View theView;
    
    public FoxnrAndrabbit(int size) {
        for(int row=0;row

2.5 接口设计模式:

package cell;

import java.awt.Graphics;

public interface Cell {
    void draw(Graphics g,int x,int y,int size);

}

实现接口:

  • 类用extends,接口用implements(一个类实现接口);
  • 类可以实现很多接口;
  • 接口可以继承接口,但不能继承类;
  • 接口不能实现接口;

面向接口的编程方式:

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

2.6 Cell和Field的关系:

  • Cell在Field中,但是Cell的很多操作需要Field的数据;
  • 方法一:
    • 让每个Cell有一个Field的管理者(Cell知道Field)
                        animal.eat(theField);
                        Cell[]neighbour = theField.getNeighbour(row,col);
                        ArrayList(Cell an:neighbour){
                            if(an instanceof Rabbit) {
                                listRabbit.add(Rabbit)an);
                            }
                        }
  • 方法二:
    • 由外部第三方来建立两者之间的联系(Cell不知道Field)

2.7 讨论:

讨论0:

  • Cell要不要知道Field ?
    • 在城堡游戏中,Handler是知道Game的;
    • 在细胞自动机中,Cell是不知道Field的;

讨论1:

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

你可能感兴趣的:(Java进阶学习笔记(十))