JAVA第三次实验

实验内容

1. XP基础

2. XP核心实践

3. 相关工具

 

 

实验步骤

(一)敏捷开发与XP

软件工程包括下列领域:软件需求分析、软件设计、软件构建、软件测试和软件维护。

标识符名字应当直观且可以拼读,可望文知意,不必进行“解码”,一般采用英文单词或其组合,便于记忆和阅读,切忌使用汉语拼音来命名,用词要准确例如“当前值”应该起名currentValue,写成nowValue就不准确了,但还凑合,写成dqz(dang qian zhi 首字母)就是笑话了。

标识符的长度“min-length && max-information”的原则,比如:maxValmaxValueUntilOverflow要好些,可以通过去元音法把变量名变短,如returnValue->rtnValmessage->msg;一般全局变量用具有说明性的名字,局部变量用短名字:单字符的名字,常见的如i,j,k等用作局部变量。   

 

(二)编码标准

编写代码一个重要的认识是“程序大多时候是给人看的”,编程标准使代码更容易阅读和理解,甚至可以保证其中的错误更少。编程标准包含:具有说明性的名字、清晰的表达式、直截了当的控制流、可读的代码和注释,以及在追求这些内容时一致地使用某些规则和惯用法的重要性。

标识符的长度“min-length && max-information”的原则,比如:maxValmaxValueUntilOverflow要好些,可以通过去元音法把变量名变短,如returnValue->rtnValmessage->msg;一般全局变量用具有说明性的名字,局部变量用短名字:单字符的名字,常见的如i,j,k等用作局部变量。

Java中的一般的命名规则有:

  • 要体现各自的含义
  • 包、类、变量用名词
  • 方法名用动宾
  • 包名全部小写,如:io,awt
  • 类名第一个字母要大写,如:HelloWorldApp
  • 变量名第一个字母要小写,如:userName
  • 方法名第一个字母要小写:setName

(三)结对编程

武西垚工作:加注释,测试代码,加图片

郑伟:写主函数,完善各模块

 

结对同学:20135332

http://www.cnblogs.com/wuxiyao/ 

拼图游戏

 

* JAVA小游戏-拼图 我做的第一个小游戏 * Cell类是继承的按钮类,并加上相应图形,形成方格 *MyCanvas是一个面板,加载Cell类的对象(方格),是这三个类中的核心 *
*/

 

import java.awt.BorderLayout; import java.awt.Button; import java.awt.Choice; import java.awt.Color; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;

 

import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel;

 

public class MyMainFrame extends JFrame implements ActionListener { MyCanvas myCanvas; JPanel panelNorth,panelPreview;//定义上方的面板,及预览所需的面板 Button start,preview,set;//定义开始,预览,设定按钮 Container container;//容器,得到内容面板
public MyMainFrame() {//初使化 container=this.getContentPane(); start=new Button("开始"); start.addActionListener(this); preview=new Button("预览"); preview.addActionListener(this); set = new Button("设置"); set.addActionListener(this); panelPreview=new JPanel(); panelPreview.setLayout(null); Icon icon=new ImageIcon("pictrue/pic_"+MyCanvas.pictureID+".jpg"); JLabel label=new JLabel(icon); label.setBounds(0,0,300,300); panelPreview.add(label);
panelNorth=new JPanel(); panelNorth.setBackground(Color.red); panelNorth.add(start); panelNorth.add(preview); panelNorth.add(set); myCanvas=new MyCanvas(); container.add(myCanvas,BorderLayout.CENTER); container.add(panelNorth,BorderLayout.NORTH); this.setTitle("拼图小游戏-明"); this.setLocation(300,200); this.setSize(308,365); this.setResizable(false); this.setVisible(true);
this.setDefaultCloseOperation(3); } public static void main(String[] args) { // TODO 自动生成方法存根 new MyMainFrame();
} public void actionPerformed(ActionEvent arg0) {//对三个按钮事件的处理 // TODO 自动生成方法存根 Button button=(Button)arg0.getSource(); if(button==start){ myCanvas.Start();
}else if(button==preview){ if(button.getLabel()=="预览"){ container.remove(myCanvas); container.add(panelPreview); panelPreview.updateUI(); container.repaint();
button.setLabel("返回"); }else{ container.remove(panelPreview); container.add(myCanvas); container.repaint(); button.setLabel("预览"); } }else if(button==set){//修改所选图片 Choice pic = new Choice(); pic.add("小猫"); pic.add("小猪"); pic.add("云"); pic.add("QQ"); pic.add("卡通"); pic.add("花");

 

int i=JOptionPane.showConfirmDialog(this, pic, "选择图片", JOptionPane.OK_CANCEL_OPTION); if(i==JOptionPane.YES_OPTION){ MyCanvas.pictureID=pic.getSelectedIndex()+1; myCanvas.reLoadPictrue(); Icon icon=new ImageIcon("pictrue/pic_"+MyCanvas.pictureID+".jpg"); JLabel label=new JLabel(icon); label.setBounds(0,0,300,300); panelPreview.removeAll(); panelPreview.add(label); panelPreview.repaint(); } } }

 

}

--------------------------------------------------

import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener;

import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JOptionPane; import javax.swing.JPanel;

public class MyCanvas extends JPanel implements MouseListener { boolean hasAddActionListener=false;//设置方格的动作监听器的标志位,TRUE为已经添加上动作事件,FALSE是尚未添加动作事件 Cell cell[];//定义方格 Rectangle cellNull;//定义空方格区域 public static int pictureID=1;//当前选择的图片代号 public MyCanvas() { this.setLayout(null); this.setSize(400,400); cellNull=new Rectangle(200,200,100,100);//空方格区域在第三行每三列 cell=new Cell[9]; Icon icon; for (int i = 0; i < 3; i++) {//为9个方格加载图片,并初使化坐标,形成三行三列 for(int j=0;j<3;j++){ icon=new ImageIcon("pictrue/pic_"+pictureID+"_"+(i*3+j+1)+".jpg"); cell[i*3+j]=new Cell(icon); cell[i*3+j].setLocation(j*100,i*100); this.add(cell[i*3+j]); } } this.remove(cell[8]);//移除最后一个多余的方格 }
public void reLoadPictrue(){//当选择其它图形进行拼图时,需重新加载新图片 Icon icon; for (int i = 0; i < 3; i++) { for(int j=0;j<3;j++){ icon=new ImageIcon("pictrue/pic_"+pictureID+"_"+(i*3+j+1)+".jpg"); cell[i*3+j].setIcon(icon); } } } public boolean isFinish(){//判断是否拼合成功 for(int i=0;i<8;i++){ int x=cell[i].getBounds().x; int y=cell[i].getBounds().y; if(y/100*3+x/100!=i) return false; } return true; }
public void Start(){//对方格进行重新排列,打乱顺序
while(cell[0].getBounds().x<=100&&cell[0].getBounds().y<=100){//当第一个方格距左上角较近时 int x=cellNull.getBounds().x; int y=cellNull.getBounds().y; int direction=(int)(Math.random()*4);//产生0-4,对应空方格的上下左右移动 if(direction==0){//空方格左移动,与左侧方格互换位置,左侧方格右移动 x-=100; if(test(x,y)){ for(int j=0;j<8;j++){ if((cell[j].getBounds().x==x)&&(cell[j].getBounds().y==y)){//依次寻找左侧的按钮 cell[j].move("RIGHT",100); cellNull.setLocation(x,y); break;//找到后跳出for循环 } } } }else if(direction==1){//RIGHT x+=100; if(test(x,y)){ for(int j=0;j<8;j++){ if((cell[j].getBounds().x==x)&&(cell[j].getBounds().y==y)){ cell[j].move("LEFT",100); cellNull.setLocation(x,y); break; } } } }else if(direction==2){//UP y-=100; if(test(x,y)){ for(int j=0;j<8;j++){ if((cell[j].getBounds().x==x)&&(cell[j].getBounds().y==y)){ cell[j].move("DOWN",100); cellNull.setLocation(x,y); break; } } } }else{//DOWN y+=100; if(test(x,y)){ for(int j=0;j<8;j++){ if((cell[j].getBounds().x==x)&&(cell[j].getBounds().y==y)){ cell[j].move("UP",100); cellNull.setLocation(x,y); break; } } } }
}
if(!hasAddActionListener)//如果尚未添加动作事件,则添加 for(int i=0;i<8;i++)//为第个方格添加动作事件,这样单击按钮就能移动了 cell[i].addMouseListener(this); hasAddActionListener=true; } private boolean test(int x,int y){ if((x>=0&&x<=200)||(y>=0&&y<=200)) return true; else return false; } // public void paint(Graphics g){ // // for(int i=0;i<=300;i+=100) // g.drawLine(0, i, 300, i); // for(int i=0;i<=300;i+=100) // g.drawLine(i, 0, i, 300); // for(int i=0;i<8;i++) // cell[i].repaint(); // }

public void mouseClicked(MouseEvent arg0) { } public void mouseEntered(MouseEvent arg0) { } public void mouseExited(MouseEvent arg0) { } public void mouseReleased(MouseEvent arg0) { } public void mousePressed(MouseEvent arg0) {//方格的鼠标事件,因为用到了MyCanvas中的一些方法,因此没有在Cell类中处理鼠标事件 Cell button=(Cell)arg0.getSource(); int x1=button.getBounds().x;//得到所单击方格的坐标 int y1=button.getBounds().y;
int x2=cellNull.getBounds().x;//得到空方格的坐标 int y2=cellNull.getBounds().y;
if(x1==x2&&y1-y2==100)//进行比较,如果满足条件则进行交换 button.move("UP",100); else if(x1==x2&&y1-y2==-100) button.move("DOWN",100); else if(x1-x2==100&y1==y2) button.move("LEFT",100); else if(x1-x2==-100&&y1==y2) button.move("RIGHT",100); else return;//不满足就不进行任何处理
cellNull.setLocation(x1,y1); this.repaint(); if(this.isFinish()){//进行是否完成的判断 JOptionPane.showMessageDialog(this,"恭喜你完成拼图,加油!"); for(int i=0;i<8;i++) cell[i].removeMouseListener(this);//如果已完成,撤消鼠标事件,鼠标单击方格不在起作用 hasAddActionListener=false; } }

}

------------------------------------------------------------------------------------------

import javax.swing.Icon; import javax.swing.JButton;
public class Cell extends JButton { Cell(Icon icon){//实际为ICON super(icon); this.setSize(100,100); }

public void move(String direction,int sleep){//方格的移动 if(direction=="UP"){ this.setLocation(this.getBounds().x,this.getBounds().y-100); }else if(direction=="DOWN"){ this.setLocation(this.getBounds().x,this.getBounds().y+100); }else if(direction=="LEFT"){ this.setLocation(this.getBounds().x-100,this.getBounds().y); }else{ this.setLocation(this.getBounds().x+100,this.getBounds().y); } }
}

 技术分享

 

(四)版本控制

技术分享

注意一点,往代码库提交的代码一定编译、运行、测试都没有问题的代码,我们上面测试代码没有问题了,就可以提交了: 如图:我们可以先用git status查看一下代码状态,显示有未跟踪的代码,并建议用git add <file>...添加,我们使用git add HelloWorld.* 把要提交的文件的信息添加到索引库中。当我们使用git commit时,git将依据索引库中的内容来进行文件的提交。这只是在本地操作,关闭实验环境,会删除代码的,如果想把代码保存到远程托管服务器中,需要使用git push实验完成前,一定不要忘了使用git push,否则就是相当于你在Word中编辑了半天文件最后却没有保存。 我们可以修改HelloWorld.java,如下图所示:

编译、运行、测试没有问题后进行提交,这儿使用的是git commit -a: ,

我们可以通过git log查看代码提技术分享交记录:

 

 

技术分享

技术分享

(五)重构

我们先看看重构的概念:

重构(Refactor),就是在不改变软件外部行为的基础上,改变软件内部的结构,使其更加易于阅读、易于维护和易于变更 。

重构中一个非常关键的前提就是“不改变软件外部行为”,它保证了我们在重构原有系统的同时,不会为原系统带来新的BUG,以确保重构的安全。如何保证不改变软件外部行为?重构后的代码要能通过单元测试。如何使其更加易于阅读、易于维护和易于变更 设计模式给出了重构的目标。

重构重要吗?你看看Eclipse菜单中有个refactor菜单就知道了,重构几乎是现代IDE的标配了:

 

我们在编码标准中说“给标识符命名”是程序员一项重要技能,以前没有这个意识,现在知道了怎么办?没问题,上图中重构的第一项功能就是Rename,可以给类、包、方法、变量改名字。 例如这有个ABC类:

这个类,类名,方法名和方法的参数名都有问题,没有注释的话是无法理解代码的。我们可以使用Eclipse中的重构功能来改名。修改方法是,用鼠标单击要改的名字,选择Eclipse中菜单中的Refactor->Rename...

重构完的效果如下:

功能不变,代码水平立马上了一个档次,体会到命名的威力了吧?

 

Eclipse中菜单中的Refactor->Encapsulate Field...,如下图:

 

注意分析一下重构前后的代码变化: 同样可以封装idage两个成员变量,结果如下:

上面第34,35行还是有问题的,每次打印学生信息都这么写代码违反了DRY原则,造成代码重复,正常的重构可以使用Eclipse中的Extract Method...,如下图:

由于Java中所有的类都有个专门的toString方法,我们使用Eclipse中Source->Generate toString()...Student类产生一个toString方法,如下图:

修改main的代码,结果如下:

大家想一想,这样重构后有什么好处?重构有什么问题吗?

我们要修改软件,万变不离其宗,无非就是四种动机:

  • 增加新功能;
  • 原有功能有BUG;
  • 改善原有程序的结构;
  • 优化原有系统的性能 。

 技术分享

 

  • 最单纯的Duplicated Code就是[同一个class内的两个方法含有相同表达式(expression)]。这时候你需要做的就是采用Extract Method提炼出重复的代码,然后让这两个地点都调用被提炼出来的那一段代码。
  • 另一种常见情况就是[两个互为兄弟(sibling)的subclasses内含有相同表达式]。要避免这种情况,只需要对两个classes都使用Extract Method,然后再对被提炼出的代码使用Pull Up Method,将它推入superclass内。
  • 如果代码之间只是类似,并非完全相同,那么就得运用Extract Method将相似部分和差异部分割开,构成单独一个方法。然后你可能发现或许可以运用Form Template Method获得一个Template Method设计模式。
  • 如果有些方法以不同的算法做相同的事,你可以择定其中较清晰的一个,并使用Substitute Algorithm将其它方法的算法替换掉。
  • 如果两个毫不相关的classes内出现Duplicaded Code,你应该考虑对其中一个使用Extract Class,将重复代码提炼到一个独立class中,然后在另一个class内使用这个新class。但是,重复代码所在的方法也可能的确只应该属于某个class,另一个class只能调用它,抑或这个方法可能属于第三个class,而另两个classes应该引用这第三个class。你必须决定这个方法放在哪儿最合适,并确保它被安置后就不会再在其它任何地方出现。

其他Bad Smell与相应的重构手法如下表所示:

Eclipse中Refactor菜单中的重构手法的应用时机如下图所示:

更完整的手法可以参考《重构》作者Martin Fowler的博客。Eclipse中基本手法的使用大家可以参考任何人都可以重构来进行学习实践。

一个完整的重构流程包括:

  1. 从版本控制系统代码库中Check out code
  2. 读懂代码(包括测试代码)
  3. 发现bad smell
  4. Refactoring
  5. 运行所有的Unit Tests
  6. 往代码库中Check in code

我们结合Git给出一个比较完整的例子。

(六)实践项目

1. 以结对编程的方式编写一个软件,Blog中要给出结对同学的Blog网址,可以拍照展现结对编程情况,可以参考一下其他学校的作业

     

结对同学:20135322

http://www.cnblogs.com/zhengwei0712/

 

2.记录TDD和重构的过程,测试代码不要少于业务代码,Eclipse中refactor菜单下的重构技能不要少于5个

 

3.团队代码要使用git在实验楼中托管,要使用结对同学中的一个同学的账号托管。

4. 程序要有GUI界面,参考用户界面和用户体验

5.程序功能从豌豆荚游戏中选择一款用Java实现,注意:团队之间项目不能有重复,课代表协调一下

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。