美文网首页
Java进阶学习笔记(十)

Java进阶学习笔记(十)

作者: 理以周 | 来源:发表于2019-07-25 15:58 被阅读0次

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<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) {//0-0.1之间的数
                    cell.reborn();
                }
            }
        }
        View view = new View(field);
        JFrame frame = new JFrame;
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//默认关闭操作:x结束操作
        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()) {
                            numOfLice++;
                        }
                    }
                    System.out.print("["+row+"]["+col+"]:");
                    System.out.print(cell.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();*
            }
        }
    }
}

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<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);
    }

}

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){
        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()]);
    }

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<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);
    }
}

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<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("Cells");
        frame.add(theView);
        frame.pack();
        frame.setVisible(true);
    }//窗口
    
    public void start(int steps) {
        for(int i=0;i<steps;i++) {
            step();
            theView.repaint();
            try {
                Thread.sleep(200);
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    publci 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
                        Cell[]neighbour = theField.getNeighbour(row,col);
                        ArrayList(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(bay!=null) {
                            theField.placeRandomAdj(row, col, (Cell)baby);
                        }
                    }else {
                        theField.remove(row,col);
                    }
                }
            }
        }
    }

}

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<Animal>来表示所有的动物,每一步遍历这个列表而非整个Field,这样做是否更好?
  • 这样就需要每个Animal知道自己在Field里的位置;

相关文章

  • Java进阶学习笔记(十)

    1、数据与表现分离--细胞自动机: 死亡:如果活着的邻居的数量<2或>3,则死亡; 新生:如果正好有3个邻居活着,...

  • 阿里资深架构师谈Java进阶攻略:7大技能+12份进阶笔记+面试

    本文整理了这份值得收藏的Java架构师进阶攻略,包括以下:7大进阶专题技能12份Java进阶学习笔记(包括Spri...

  • Java进阶

    注:采转归档,自己学习查询使用 Java进阶01 String类Java进阶02 异常处理Java进阶03 IO基...

  • JavaScript学习笔记(五)

    慕课网JavaScript进阶篇第9章学习笔记 JavaScript进阶篇—第9章 JavaScript学习笔记(...

  • Java进阶学习笔记终篇

    1、异常: 1.1 捕捉异常:数组下标越界 1.2 异常捕捉机制: 捕捉异常: 异常发生并不意味着程序一定要终止:...

  • Java进阶学习笔记(四)

    1.对象的识别: 2.对象交互:(时钟中小时与分钟之间的交互) 一个类表达两个对象;且没有直接联系; 3.封闭的访...

  • Java进阶学习笔记(五)

    1.类变量: 2.类函数:static的函数可以直接调用,其他的函数必须要对象。 3.记事本: 能存储记录; 不限...

  • Java进阶学习笔记(六)

    1.集合SET: 2.HASH表:penny--nickel--dime--quarter--half-dolla...

  • Java进阶学习笔记(八)

    1.多态变量: 1.1 子类和子类型: 类定义了类型; 子类定义了子类型; 子类的对象可以被当做父类的对象来使用;...

  • JAVA进阶学习笔记:反射

    一、定义 在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。 二、功能 1.在运...

网友评论

      本文标题:Java进阶学习笔记(十)

      本文链接:https://www.haomeiwen.com/subject/tykhrctx.html