java实验三 敏捷开发与XP实践

一、实验内容

 

(一)敏捷开发与XP

 

      软件开发流程的目的是为了提高软件开发、运营、维护的效率,并提高软件的质量、用户满意度、可靠性和软件的可维护性。 光有各种流程的思想是不够的,我们还要有一系列的工具来保证这些思想能够在实践中有效率地运作。一个常见的公式是:软件工程=开发流程+工具。敏捷开发(Agile Development)是一种以人为核心、迭代、循序渐进的开发方法。“敏捷流程”是一系列价值观和方法论的集合。

 

其中,极限编程(eXtreme Programming,XP)是 是一种全新而快捷的软件开发方法。XP团队使用现场客户、特殊计划方法和持续测试来提供快速的反馈和全面的交流:

 

  • XP是以开发符合客户需要的软件为目标而产生的一种方法论
  • XP是一种以实践为基础的软件工程过程和思想
  • XP认为代码质量的重要程度超出人们一般所认为的程度
  • XP特别适合于小型的有责任心的、自觉自励的团队开发需求不确定或者迅速变化的软件

 

XP软件开发是什么样的通过 XP准则来表达:

 

  • 沟通 :XP认为项目成员之间的沟通是项目成功的关键,并把沟通看作项目中间协调与合作的主要推动因素。
  • 简单 :XP假定未来不能可靠地预测,在现在考虑它从经济上是不明智的,所以不应该过多考虑未来的问题而是应该集中力量解决燃眉之急。
  • 反馈 :XP认为系统本身及其代码是报告系统开发进度和状态的可靠依据。系统开发状态的反馈可以作为一种确定系统开发进度和决定系统下一步开发方向的手段。
  • 勇气:代表了XP认为人是软件开发中最重要的一个方面的观点。在一个软件产品的开发中人的参与贯穿其整个生命周期,是人的勇气来排除困境,让团队把局部的最优抛之脑后,达到更重大的目标。表明了XP对“人让项目取得成功”的基本信任态度。

 

一项实践在XP环境中成功使用的依据通过XP的法则呈现,包括:快速反馈、假设简单性、递增更改、提倡更改、优质工作。

 

XP软件开发的基石是XP的活动,包括:编码、测试、倾听、设计。

 

 

(二)编码标准

 

编程标准包含:具有说明性的名字、清晰的表达式、直截了当的控制流、可读的代码和注释,以及在追求这些内容时一致地使用某些规则和惯用法的重要性。

 

程序没有最基本的缩进,让人读起来很费劲,这个问题在Eclipse中比较容易解决,我们单击Eclipse菜单中的source->Format 或用快捷键Ctrl+Shift+F就可以按Eclipse规定的规范缩进。

代码标准中很重要的一项是如何给包、类、变量、方法等标识符命名,能很好的命名可以让自己的代码立马上升一个档次。Java中的一般的命名规则有:

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

方法名第一个字母要小写:setName 

(三)结对编程

结对编程是XP中的重要实践。在结对编程模式下,一对程序员肩并肩、平等地、互补地进行开发工作。他们并排坐在一台电脑前,面对同一个显示器,使用同一个键盘、同一个鼠标一起工作。他们一起分析,一起设计,一起写测试用例,一起编码,一起做单元测试,一起做集成测试,一起写文档等。 结对编程中有两个角色:

  • 驾驶员(Driver)是控制键盘输入的人。
  • 领航员(Navigator)起到领航、提醒的作用。

如何结对编程,为何要结对编程,重点是:

  • 驾驶员:写设计文档,进行编码和单元测试等XP开发流程。
  • 领航员:审阅驾驶员的文档、驾驶员对编码等开发流程的执行;考虑单元测试的覆盖率;思考是否需要和如何重构;帮助驾驶员解决具体的技术问题。
  • 驾驶员和领航员不断轮换角色,不要连续工作超过一小时,每工作一小时休息15分钟。领航员要控制时间。
  • 主动参与。任何一个任务都首先是两个人的责任,也是所有人的责任。没有“我的代码”、“你的代码”或“他/她的代码”,只有“我们的代码”。
  • 只有水平上的差距,没有级别上的差异。两人结对,尽管可能大家的级别资历不同,但不管在分析、设计或编码上,双方都拥有平等的决策权利。

团队精神是好多地方都强调的一个精神,最小的团队就是一对一的二人团队了,培养团队精神从结对编程开始吧。社会生活中人与人相处最重要的是诚信,有同理心,互利。结对编程中大家会出现分歧,如何更有效地合作要做到对事不对人

(四)版本控制

XP的集体所有制意味着每个人都对所有的代码负责;这一点,反过来又意味着每个人都可以更改代码的任意部分。结对编程对这一实践贡献良多:借由在不同的结对中工作,所有的程序员都能看到完全的代码。集体所有制的一个主要优势是提升了开发程序的速度,因为一旦代码中出现错误,任何程序员都能修正它。 这意味着代码要放到一个大家都能方便获取的地方,我们叫代码仓库。这引出另外一个话题叫版本控制(Version Control)。

不论是对于团队还是个体,版本控制都提供了很多好处。

  • 版本控制提供项目级的      undo(撤销)      功能:      没有什么事情是终结版本, 任何错误必须很容易回滚。 假设你在使用世界上最复杂的文字处理系统。 它具备了所有的能想到的功能,就是没有支持 DELETE(删除) 键。想象你打字的时候得多么的谨慎和缓慢吧,      特别是一篇超大的文档的快临近末尾的时候, 一个不小心就要重头再来(试想你选中所有的文字, 不小心按了 DELETE 键, 因为没有撤销功能,只好重新录入)。编辑文字和版本控制相同,任何时候都需要回滚,无论是一个小时, 一天, 还是一周, 这让你的团队工作自由快速的工作, 而且对于修正错误也非常自信。
  • 版本控制允许多人在同一代码上工作,      只要遵守一定的控制原则就行。 再也不会发生诸如一个人覆盖了另一个人编辑的代码,导致那个人的修改无效这样的情况。
  • 版本控制系统保存了过去所作的修改的历史记录。如果你遭遇到一些惊讶的代码,通过版本控制系统可以很容易找出是谁干的, 修改了什么, 修改的时间, 如果幸运的话,还能找出原因。
  • 版本控制系统还支持在主线上开发的同时发布多个软件版本。在软件发布的时候也不需要整个团队的停止工作,不需要冻结代码。
  • 版本控制也是项目级的时间机器,你可以选择任何一个时间, 精确地查看项目在当时的情况。 这对研究非常有用, 也是重现以前某个有问题的发布版本的基础

(五)重构

我们先看看重构的概念:

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

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

(六)实践项目

1、项目简介:编辑一个简单的连连看项目小游戏。

需要实现(1)一个6行*5列的主面板,显示参与游戏的数;(2)根据玩家所选择的两个数,进行判断,这两个数是否一致,若一致则消去,否则不变,直至所有数全部消除,游戏即为结束;(3)当玩家找不到一样的数时,可以使用“重列”按钮对当前游戏进行重新排列;(4)当玩家选择“再来一局”按钮时,游戏重新开始;(5)当玩家选择退出按钮时,游戏结束。

2、游戏代码

package lianliankan;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class lianliankan implements ActionListener
{
JFrame mainFrame; //主面板
Container thisContainer;
JPanel centerPanel,southPanel,northPanel; //子面板
JButton diamondsButton[][] = new JButton[6][5];//游戏按钮数组
JButton exitButton,resetButton,newlyButton; //退出,重列,重新开始按钮
JLabel fractionLable=new JLabel("0"); //分数标签
JButton firstButton,secondButton; //分别记录两次被选中的按钮
int grid[][] = new int[8][7];//储存游戏按钮位置
static boolean pressInformation=false; //判断是否有按钮被选中
int x0=0,y0=0,x=0,y=0,fristMsg=0,secondMsg=0,validateLV; //游戏按钮的位置坐标
int i,j,k,n;//消除方法控制
public void init(){
mainFrame=new JFrame("JKJ连连看");
thisContainer = mainFrame.getContentPane();
thisContainer.setLayout(new BorderLayout());
centerPanel=new JPanel();
southPanel=new JPanel();
northPanel=new JPanel();
thisContainer.add(centerPanel,"Center");
thisContainer.add(southPanel,"South");
thisContainer.add(northPanel,"North");
centerPanel.setLayout(new GridLayout(6,5));
for(int cols = 0;cols < 6;cols++){
for(int rows = 0;rows < 5;rows++ ){
diamondsButton[cols][rows]=new JButton(String.valueOf(grid[cols+1][rows+1]));
diamondsButton[cols][rows].addActionListener(this);
centerPanel.add(diamondsButton[cols][rows]);
}
}
exitButton=new JButton("退出");
exitButton.addActionListener(this);
resetButton=new JButton("重列");
resetButton.addActionListener(this);
newlyButton=new JButton("再来一局");
newlyButton.addActionListener(this);
southPanel.add(exitButton);
southPanel.add(resetButton);
southPanel.add(newlyButton);
fractionLable.setText(String.valueOf(Integer.parseInt(fractionLable.getText())));
northPanel.add(fractionLable);
mainFrame.setBounds(280,100,500,450);
mainFrame.setVisible(true);
}
public void randomBuild() {
int randoms,cols,rows;
for(int twins=1;twins<=15;twins++) {
randoms=(int)(Math.random()*25+1);
for(int alike=1;alike<=2;alike++) {
cols=(int)(Math.random()*6+1);
rows=(int)(Math.random()*5+1);
while(grid[cols][rows]!=0) {
cols=(int)(Math.random()*6+1);
rows=(int)(Math.random()*5+1);
}
this.grid[cols][rows]=randoms;
}
}
}
public void fraction(){
fractionLable.setText(String.valueOf(Integer.parseInt(fractionLable.getText())+100));
}
public void reload() {
int save[] = new int[30];
int n=0,cols,rows;
int grid[][]= new int[8][7];
for(int i=0;i<=6;i++) {
for(int j=0;j<=5;j++) {
if(this.grid[i][j]!=0) {
save[n]=this.grid[i][j];
n++;
}
}
}
n=n-1;
this.grid=grid;
while(n>=0) {
cols=(int)(Math.random()*6+1);
rows=(int)(Math.random()*5+1);
while(grid[cols][rows]!=0) {
cols=(int)(Math.random()*6+1);
rows=(int)(Math.random()*5+1);
}
this.grid[cols][rows]=save[n];
n--;
}
mainFrame.setVisible(false);
pressInformation=false; //这里一定要将按钮点击信息归为初始
init();
for(int i = 0;i < 6;i++){
for(int j = 0;j < 5;j++ ){
if(grid[i+1][j+1]==0)
diamondsButton[i][j].setVisible(false);
}
}
}
public void estimateEven(int placeX,int placeY,JButton bz) {
if(pressInformation==false) {
x=placeX;
y=placeY;
secondMsg=grid[x][y];
secondButton=bz;
pressInformation=true;
}
else {
x0=x;
y0=y;
fristMsg=secondMsg;
firstButton=secondButton;
x=placeX;
y=placeY;
secondMsg=grid[x][y];
secondButton=bz;
if(fristMsg==secondMsg && secondButton!=firstButton){
xiao();
}
}
}
public void xiao() { //相同的情况下能不能消去。仔细分析,不一条条注释
if((x0==x &&(y0==y+1||y0==y-1)) || ((x0==x+1||x0==x-1)&&(y0==y))){ //判断是否相邻
remove();
}
else{
for (j=0;j<7;j++ ) {
if (grid[x0][j]==0){ //判断第一个按钮同行哪个按钮为空
if (y>j) { //如果第二个按钮的Y坐标大于空按钮的Y坐标说明第一按钮在第二按钮左边
for (i=y-1;i>=j;i-- ){ //判断第二按钮左侧直到第一按钮中间有没有按钮
if (grid[x][i]!=0) {
k=0;
break;
}
else{ k=1; } //K=1说明通过了第一次验证
}
if (k==1) {
linePassOne();
}
}
if (y<j){ //如果第二个按钮的Y坐标小于空按钮的Y坐标说明第一按钮在第二按钮右边
for (i=y+1;i<=j ;i++ ){ //判断第二按钮左侧直到第一按钮中间有没有按钮
if (grid[x][i]!=0){
k=0;
break;
}
else { k=1; }
}
if (k==1){
linePassOne();
}
}
if (y==j ) {
linePassOne();
}
}
if (k==2) {
if (x0==x) {
remove();
}
if (x0<x) {
for (n=x0;n<=x-1;n++ ) {
if (grid[n][j]!=0) {
k=0;
break;
}
if(grid[n][j]==0 && n==x-1) {
remove();
}
}
}
if (x0>x) {
for (n=x0;n>=x+1 ;n-- ) {
if (grid[n][j]!=0) {
k=0;
break;
}
if(grid[n][j]==0 && n==x+1) {
remove();
}
}
}
}
}
for (i=0;i<8;i++ ) { //列
if (grid[i][y0]==0) {
if (x>i) {
for (j=x-1;j>=i ;j-- ) {
if (grid[j][y]!=0) {
k=0;
break;
}
else { k=1; }
}
if (k==1) {
rowPassOne();
}
}
if (x<i) {
for (j=x+1;j<=i;j++ ) {
if (grid[j][y]!=0) {
k=0;
break;
}
else { k=1; }
}
if (k==1) {
rowPassOne();
}
}
if (x==i) {
rowPassOne();
}
}
if (k==2){
if (y0==y) {
remove();
}
if (y0<y) {
for (n=y0;n<=y-1 ;n++ ) {
if (grid[i][n]!=0) {
k=0;
break;
}
if(grid[i][n]==0 && n==y-1) {
remove();
}
}
}
if (y0>y) {
for (n=y0;n>=y+1 ;n--) {
if (grid[i][n]!=0) {
k=0;
break;
}
if(grid[i][n]==0 && n==y+1) {
remove();
}
}
}
}
}
}
}
public void linePassOne(){
if (y0>j){ //第一按钮同行空按钮在左边
for (i=y0-1;i>=j ;i-- ){ //判断第一按钮同左侧空按钮之间有没按钮
if (grid[x0][i]!=0) {
k=0;
break;
}
else { k=2; } //K=2说明通过了第二次验证
}
}
if (y0<j){ //第一按钮同行空按钮在与第二按钮之间
for (i=y0+1;i<=j ;i++){
if (grid[x0][i]!=0) {
k=0;
break;
}
else{ k=2; }
}
}
}
public void rowPassOne(){
if (x0>i) {
for (j=x0-1;j>=i ;j-- ) {
if (grid[j][y0]!=0) {
k=0;
break;
}
else { k=2; }
}
}
if (x0<i) {
for (j=x0+1;j<=i ;j++ ) {
if (grid[j][y0]!=0) {
k=0;
break;
}
else { k=2; }
}
}
}
public void remove(){
firstButton.setVisible(false);
secondButton.setVisible(false);
fraction();
pressInformation=false;
k=0;
grid[x0][y0]=0;
grid[x][y]=0;
}
public void actionPerformed(ActionEvent e) {
if(e.getSource()==newlyButton){
int grid[][] = new int[8][7];
this.grid = grid;
randomBuild();
mainFrame.setVisible(false);
pressInformation=false;
init();
}
if(e.getSource()==exitButton)
System.exit(0);
if(e.getSource()==resetButton)
reload();
for(int cols = 0;cols < 6;cols++){
for(int rows = 0;rows < 5;rows++ ){
if(e.getSource()==diamondsButton[cols][rows])
estimateEven(cols+1,rows+1,diamondsButton[cols][rows]);
}
}
}
public static void main(String[] args) {
lianliankan llk = new lianliankan();
llk.randomBuild();
llk.init();
}
}

3、小组分工情况(小组成员:20135116王玮怡 blog地址:http://www.cnblogs.com/wwy-20135116/ ,20135109高艺桐)

高艺桐:编写判断操作,判断玩家所选两个数是否一致,若一致则消去,否则界面不变。

王玮怡:编写页面空间的设置,如游戏中“重列”、“再来一局”,“退出”按钮。

4、测试结果显示截图

(七)实验时间

 

步骤

耗时

百分比

需求分析

1h

25%

设计

30min

12.5%

代码实现

1.5min

37.5%

测试

0

0%

分析总结

1h

25%

 

(八)实验总结

  通过这次实验学习到重构的raname:如何修改名称。以前在编程序时名称不小心打错,或者是需要对名称进行修改使它更有意义时,现在可以快捷简便的进行修改。我觉得对以后代码的编写特别的实用,有意义。我还学会了重构的封装功能,可以对成员变量进行封装,以及Source->Generate toString()... 给Student类产生一个toString方法。这样优化了实验的代码,使代码更加简洁明了。在实验中我也遇到了很多的问题,比如在进行重构的封装功能时,因为没有选中age、name、id使代码封装失败,不过通过请教做完实验的同学最后问题还是迎刃而解了。

  本次的java实验让我学会了优化代码,不仅能使使用者看着简洁舒服,还能增添完成代码的速率,我从本次实验中获益匪浅。

 

 

 

 

posted on 2015-06-04 22:49  20135109  阅读(406)  评论(0编辑  收藏  举报