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<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里的位置;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,085评论 1 32
  • 对象的创建与销毁 Item 1: 使用static工厂方法,而不是构造函数创建对象:仅仅是创建对象的方法,并非Fa...
    孙小磊阅读 1,963评论 0 3
  • 《商山四皓图》轴,清,黄慎绘,纸本,设色,纵120.2cm,横68.3cm,故宫博物院藏。 此图描绘的是秦末东园公...
    阳阳说画阅读 620评论 0 2
  • 文/雁南飞
    雁南飞fly阅读 1,073评论 13 30
  • ​--谨以此篇文章献给即将面临高考的高三党们 ​--同时也献给那些毕业了的学哥学姐们和还没毕业的学弟学妹们 ​ 时...
    夏雨夜阅读 625评论 0 0