实验三 敏捷开发与XP实践
实验内容
1. XP基础
2. XP核心实践
3. 相关工具
实验步骤
(一)敏捷开发与XP
软件工程是把系统的、有序的、可量化的方法应用到软件的开发、运营和维护上的过程。软件工程包括下列领域:软件需求分析、软件设计、软件构建、软件测试和软件维护。 人们在开发、运营、维护软件的过程中有很多技术、做法、习惯和思想体系。软件工程把这些相关的技术和过程统一到一个体系中,叫“软件开发流程”。软件开发流程的目的是为了提高软件开发、运营、维护的效率,并提高软件的质量、用户满意度、可靠性和软件的可维护性。 光有各种流程的思想是不够的,我们还要有一系列的工具来保证这些思想能够在实践中有效率地运作。软件开发很重要的一点不是看你能对多少理论讲的头头是道,还要看你对相关工具应用的如何,比如Java中单元测试要和JUnit的应用结合起来,建模要和Umbrello或StarUML的应用结合起来。编程学习是一个习而学的过程。 一个常见的公式是:软件工程=开发流程+工具 邹欣老师给出的两个公式:软件=程序+软件工程和软件企业=软件+商业模式 开发流程大家可以参考学习邹欣老师的软件团队和开发流程。常见的开发流程有:
- RUP(Rational Unified Process)
- PSP(Personal Software Process )
- TSP(Team Software Process )
- Agile Process
- ……
敏捷开发(Agile Development)是一种以人为核心、迭代、循序渐进的开发方法。“敏捷流程”是一系列价值观和方法论的集合。从2001年开始,一些软件界的专家开始倡导“敏捷”的价值观和流程,他们肯定了流行做法的价值,但是强调敏捷的做法更能带来价值。 其中,极限编程(eXtreme Programming,XP)是 是一种全新而快捷的软件开发方法。XP团队使用现场客户、特殊计划方法和持续测试来提供快速的反馈和全面的交流:
- XP是以开发符合客户需要的软件为目标而产生的一种方法论
- XP是一种以实践为基础的软件工程过程和思想
- XP认为代码质量的重要程度超出人们一般所认为的程度
- XP特别适合于小型的有责任心的、自觉自励的团队开发需求不确定或者迅速变化的软件
XP软件开发是什么样的通过 XP准则来表达:
- 沟通 :XP认为项目成员之间的沟通是项目成功的关键,并把沟通看作项目中间协调与合作的主要推动因素。
- 简单 :XP假定未来不能可靠地预测,在现在考虑它从经济上是不明智的,所以不应该过多考虑未来的问题而是应该集中力量解决燃眉之急。
- 反馈 :XP认为系统本身及其代码是报告系统开发进度和状态的可靠依据。系统开发状态的反馈可以作为一种确定系统开发进度和决定系统下一步开发方向的手段。
- 勇气:代表了XP认为人是软件开发中最重要的一个方面的观点。在一个软件产品的开发中人的参与贯穿其整个生命周期,是人的勇气来排除困境,让团队把局部的最优抛之脑后,达到更重大的目标。表明了XP对“人让项目取得成功”的基本信任态度。
一项实践在XP环境中成功使用的依据通过XP的法则呈现,包括:快速反馈、假设简单性、递增更改、提倡更改、优质工作。
XP软件开发的基石是XP的活动,包括:编码、测试、倾听、设计。
(二)编码标准
编写代码一个重要的认识是“程序大多时候是给人看的”,编程标准使代码更容易阅读和理解,甚至可以保证其中的错误更少。编程标准包含:具有说明性的名字、清晰的表达式、直截了当的控制流、可读的代码和注释,以及在追求这些内容时一致地使用某些规则和惯用法的重要性。
编码标准中的版式就是一个很好的例子,版式虽然不会影响程序的功能,但会影响可读性。程序的版式追求清晰、美观,是程序风格的重要因素。
三)结对编程
结对编程是XP中的重要实践。在结对编程模式下,一对程序员肩并肩、平等地、互补地进行开发工作。他们并排坐在一台电脑前,面对同一个显示器,使用同一个键盘、同一个鼠标一起工作。他们一起分析,一起设计,一起写测试用例,一起编码,一起做单元测试,一起做集成测试,一起写文档等。 结对编程中有两个角色:
- 驾驶员(Driver)是控制键盘输入的人。
- 领航员(Navigator)起到领航、提醒的作用。
如何结对编程,为何要结对编程,大家参考一下结对编程和两人合作,重点是:
- 驾驶员:写设计文档,进行编码和单元测试等XP开发流程。
- 领航员:审阅驾驶员的文档、驾驶员对编码等开发流程的执行;考虑单元测试的覆盖率;思考是否需要和如何重构;帮助驾驶员解决具体的技术问题。
- 驾驶员和领航员不断轮换角色,不要连续工作超过一小时,每工作一小时休息15分钟。领航员要控制时间。
- 主动参与。任何一个任务都首先是两个人的责任,也是所有人的责任。没有“我的代码”、“你的代码”或“他/她的代码”,只有“我们的代码”。
- 只有水平上的差距,没有级别上的差异。两人结对,尽管可能大家的级别资历不同,但不管在分析、设计或编码上,双方都拥有平等的决策权利。
团队精神是好多地方都强调的一个精神,最小的团队就是一对一的二人团队了,培养团队精神从结对编程开始吧。社会生活中人与人相处最重要的是诚信,有同理心,互利。结对编程中大家会出现分歧,如何更有效地合作要做到对事不对人,掌握这些是可以终生受益的,如何影响小伙伴,大家参考一下两人合作:要会做汉堡包。
(四)版本控制
XP的集体所有制意味着每个人都对所有的代码负责;这一点,反过来又意味着每个人都可以更改代码的任意部分。结对编程对这一实践贡献良多:借由在不同的结对中工作,所有的程序员都能看到完全的代码。集体所有制的一个主要优势是提升了开发程序的速度,因为一旦代码中出现错误,任何程序员都能修正它。 这意味着代码要放到一个大家都能方便获取的地方,我们叫代码仓库。这引出另外一个话题叫版本控制(Version Control)。
不论是对于团队还是个体,版本控制都提供了很多好处。
- 版本控制提供项目级的 undo(撤销) 功能: 没有什么事情是终结版本, 任何错误必须很容易回滚。 假设你在使用世界上最复杂的文字处理系统。 它具备了所有的能想到的功能,就是没有支持 DELETE(删除) 键。想象你打字的时候得多么的谨慎和缓慢吧, 特别是一篇超大的文档的快临近末尾的时候, 一个不小心就要重头再来(试想你选中所有的文字, 不小心按了 DELETE 键, 因为没有撤销功能,只好重新录入)。编辑文字和版本控制相同,任何时候都需要回滚,无论是一个小时, 一天, 还是一周, 这让你的团队工作自由快速的工作, 而且对于修正错误也非常自信。
- 版本控制允许多人在同一代码上工作, 只要遵守一定的控制原则就行。 再也不会发生诸如一个人覆盖了另一个人编辑的代码,导致那个人的修改无效这样的情况。
- 版本控制系统保存了过去所作的修改的历史记录。如果你遭遇到一些惊讶的代码,通过版本控制系统可以很容易找出是谁干的, 修改了什么, 修改的时间, 如果幸运的话,还能找出原因。
- 版本控制系统还支持在主线上开发的同时发布多个软件版本。在软件发布的时候也不需要整个团队的停止工作,不需要冻结代码。
- 版本控制也是项目级的时间机器,你可以选择任何一个时间, 精确地查看项目在当时的情况。 这对研究非常有用, 也是重现以前某个有问题的发布版本的基础
(五)重构
- 我们先看看重构的概念:
重构(Refactor),就是在不改变软件外部行为的基础上,改变软件内部的结构,使其更加易于阅读、易于维护和易于变更。
重构中一个非常关键的前提就是“不改变软件外部行为”,它保证了我们在重构原有系统的同时,不会为原系统带来新的BUG,以确保重构的安全。如何保证不改变软件外部行为?重构后的代码要能通过单元测试。如何使其更加易于阅读、易于维护和易于变更 ?设计模式给出了重构的目标。
实验截图:
重构实例 :
(六)实践项目
我的队友是20135325刘虹辰,我们结对实验拼图游戏
代码分为三段
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); } }
}
编译成果:
队友20135325 链接:http://www.cnblogs.com/java44/
实验心得: 在本次实验中 由于粗心在注册的时候出现了e问题 所以导致我重新祖册了实验楼账号重新做实验 在游戏设计环节 我由于能力有限 和队友没有完整自己编出代码
以后会细心并且好好学习