实验三 敏捷开发与Xp实践
2015-10-18 21:08 20159213-杨凤 阅读(195) 评论(0) 编辑 收藏 举报北京电子科技学院
实 验 报 告
课程:移动平台应用开发实践 班级:201592 姓名:杨凤 学号:20159213
成绩:___________ 指导老师:娄嘉鹏 实验日期 :2015.10.17
实验名称: Java敏捷开发与XP实践
实验内容: 1、XP基础 2、XP核心实践 3、相关工具
实验步骤
(一)敏捷开发与XP
1.敏捷开发(Agile Development)是一种以人为核心、迭代、循序渐进的开发方法。
2.常见的开发流程有:
- RUP(Rational Unified Process)
- PSP(Personal Software Process )
- TSP(Team Software Process )
- Agile Process
3.XP软件开发的准则:
- 沟通 :XP认为项目成员之间的沟通是项目成功的关键,并把沟通看作项目中间协调与合作的主要推动因素。
- 简单 :XP假定未来不能可靠地预测,在现在考虑它从经济上是不明智的,所以不应该过多考虑未来的问题而是应该集中力量解决燃眉之急。
- 反馈 :XP认为系统本身及其代码是报告系统开发进度和状态的可靠依据。系统开发状态的反馈可以作为一种确定系统开发进度和决定系统下一步开发方向的手段。
- 勇气:代表了XP认为人是软件开发中最重要的一个方面的观点。在一个软件产品的开发中人的参与贯穿其整个生命周期,是人的勇气来排除困境,让团队把局部的最优抛之脑后,达到更重大的目标。表明了XP对“人让项目取得成功”的基本信任态度。
4.XP软件开发的基石是XP的活动包括:编码、测试、倾听、设计。
(二)编码标准
编写代码一个重要的认识是“程序大多时候是给人看的”,编程标准使代码更容易阅读和理解,甚至可以保证其中的错误更少。编程标准包含:具有说明性的名字、清晰的表达式、直截了当的控制流、可读的代码和注释,以及在追求这些内容时一致地使用某些规则和惯用法的重要性。编码标准中的版式就是一个很好的例子,版式虽然不会影响程序的功能,但会影响可读性。程序的版式追求清晰、美观,是程序风格的重要因素。
我们看程序没有缩进的例子:
这个编码让人读起来比较费劲,这个问题在Eclipse通过菜单中的source->Format或者快捷键Ctrl+Shit+F就能让程序自动缩进。
这两张图进行比较,第二张是不是更有可读性,看起来更清晰。所以编程要注意程序结构的可读性。
(三)结对编程
结对编程两个人的角色和作用:
- 驾驶员(Driver)是控制键盘输入的人。
- 领航员(Navigator)起到领航、提醒的作用。
如何结对编程,为何要结对编程:
- 驾驶员:写设计文档,进行编码和单元测试等XP开发流程。
- 领航员:审阅驾驶员的文档、驾驶员对编码等开发流程的执行;考虑单元测试的覆盖率;思考是否需要和如何重构;帮助驾驶员解决具体的技术问题。
- 驾驶员和领航员不断轮换角色,不要连续工作超过一小时,每工作一小时休息15分钟。领航员要控制时间。
- 主动参与。任何一个任务都首先是两个人的责任,也是所有人的责任。没有“我的代码”、“你的代码”或“他/她的代码”,只有“我们的代码”。
- 只有水平上的差距,没有级别上的差异。两人结对,尽管可能大家的级别资历不同,但不管在分析、设计或编码上,双方都拥有平等的决策权利。
(四)版本控制
XP在结对编程中有很多优势,如果一旦代码有问题,任何程序员都能修正它。这意味着代码要放到一个大家都能方便取得的地方,我们称为代码库。我们就能引出另一个话题:版本控制。以下是实验的过程:
我们给一个HelloWorld的例子,首先进入实验楼Code目录建立一个shiyanlou_cs212目录并创建HelloWorld目录和编辑HelloWOrld.java。如下图
在上一部没有问题下,我们可以提交
编好的程序必须提交保存,操作如下:
我们也可以修改,我们修改并运行如下
(五)重构
重构(Refactor),就是在不改变软件外部行为的基础上,改变软件内部的结构,使其更加易于阅读、易于维护和易于变更 。重构中一个非常关键的前提就是“不改变软件外部行为”,它保证了我们在重构原有系统的同时,不会为原系统带来新的BUG,以确保重构的安全。如何保证不改变软件外部行为?重构后的代码要能通过单元测试。如何使其更加易于阅读、易于维护和易于变更 ?设计模式给出了重构的目标。
在Eclipse 中Rename ,可以给类、包、方法、变量改名字。以ABC为例
这个类,类名,方法名和方法的参数名都有问题,没有注释的话是无法理解代码的。我们可以使用Eclipse中的重构功能来改名。修改方法是,用鼠标单击要改的名字,选择Eclipse中菜单中的Refactor->Rename:
学过C语言的学生学Java时常犯的毛病是不会封装,该用类的地方都用了结构体。比如要定义一个类Student,会出现这样的代码:
Eclipse中菜单中的Refactor->Encapsulate Field
由于Java中所有的类都有个专门的toString方法,我们使用Eclipse中Source->Generate
toString()... 给Student类产生一个toString方法,如下图:
经过main的修改运行结果如下所示:
(六)实践项目
我们组做的实验是扫雷;代码如下:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
class Bomb extends JButton {
private static final long serialVersionUID = 1L;
public int num_x, num_y; // 第几号方块
public int BombRoundCount; // 周围雷数
public boolean isBomb; // 是否为雷
public boolean isClicked; // 是否被点击
public int BombFlag; // 探雷标记
public boolean isRight; // 是否点击右键
public Bomb(int x, int y) {
BombFlag = 0;
num_x = x;
num_y = y;
BombRoundCount = 0;
isBomb = false;
isClicked = false;
isRight = false;
}
}
/* 窗口及算法实现类 */
class MainBomb extends JFrame implements ActionListener, MouseListener {
private static final long serialVersionUID = 1L;
public JTextField text;
public Label nowBomb, setBomb;
public int BlockNum, BombNum; // 当前方块数当前雷数
public Icon icon_bomb = new ImageIcon("Bomb.gif"); // 踩雷
public Icon icon_bomb_big = new ImageIcon("bomb_big.gif"); // 踩雷标记
public Icon icon_flag = new ImageIcon("flag.gif"); // 雷标记
public Icon icon_question = new ImageIcon("question.gif"); // 疑惑是否有雷
public JButton start = new JButton(" 开始 ");
public Panel MenuPamel = new Panel();
public Panel mainPanel = new Panel();
public Bomb[][] bombButton;
/* 界面设计 */
public MainBomb() {
super("扫雷 杨凤孙楠 ");
BlockNum = 64;
BombNum = 10;
Container c = getContentPane();
c.setBackground(Color.gray);
c.setLayout(new BorderLayout());
text = new JTextField("10 ", 3);
nowBomb = new Label("当前雷数" + " " + BombNum + "");
setBomb = new Label("设置地雷数");
start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
BombNum = Integer.parseInt(text.getText().trim());
if (BombNum >= 10 && BombNum < 50)
replay();
else {
new JOptionPane();
JOptionPane.showMessageDialog(null, "你设置的地雷数太多了,请重设!",
"错误", 2);
}
}
});
MenuPamel.add(setBomb);
MenuPamel.add(text);
MenuPamel.add(start);
MenuPamel.add(nowBomb);
c.add(MenuPamel, "North");
mainPanel.setLayout(new GridLayout((int) Math.sqrt(BlockNum),
(int) Math.sqrt(BlockNum)));
bombButton = new Bomb[(int) Math.sqrt(BlockNum)][];
for (int i = 0; i < (int) Math.sqrt(BlockNum); i++) {
bombButton[i] = new Bomb[(int) Math.sqrt(BlockNum)];
}
for (int i = 0; i < (int) Math.sqrt(BlockNum); i++)
for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {
bombButton[i][j] = new Bomb(i, j);
bombButton[i][j].setForeground(Color.gray);
bombButton[i][j].addActionListener(this);
bombButton[i][j].addMouseListener(this);
}
for (int i = 0; i < (int) Math.sqrt(BlockNum); i++)
for (int j = 0; j < (int) Math.sqrt(BlockNum); j++)
mainPanel.add(bombButton[i][j]);
c.add(mainPanel, "Center");
startBomb();
setSize(400, 400);
setLocation(350, 200);
setResizable(false);
}
/* 布雷 *
public void startBomb() {
for (int i = 0; i < BombNum; i++) {
int x = (int) (Math.random() * (int) (Math.sqrt(BlockNum) - 1));
int y = (int) (Math.random() * (int) (Math.sqrt(BlockNum) - 1));
if (bombButton[x][y].isBomb == true)
i--;
else
bombButton[x][y].isBomb = true;
}
}
/* 重新开始 *
public void replay() {
nowBomb.setText("当前雷数" + " " + BombNum + "");
for (int i = 0; i < (int) Math.sqrt(BlockNum); i++)
for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {
bombButton[i][j].isBomb = false;
bombButton[i][j].isClicked = false;
bombButton[i][j].setEnabled(true);
bombButton[i][j].setText("");
bombButton[i][j].setIcon(null);
}
startBomb();
}
public void isWin() {
int findBomb = 0; // 找到的地雷数
for (int i = 0; i < (int) Math.sqrt(BlockNum); i++)
for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {
if (bombButton[i][j].isBomb == true
&& bombButton[i][j].isRight == true)
findBomb++;
}
if (findBomb == Integer.parseInt(text.getText().trim())) {
new JOptionPane();
JOptionPane.showMessageDialog(this, "你挖完了所有的雷,你胜利了!", "你胜利了", 2);
}
}
public void CountRoundBomb() {
for (int i = 0; i < (int) Math.sqrt(BlockNum); i++) {
for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {
int count = 0;
// 当需要检测的单元格本身无地雷的情况下,统计周围的地雷个数
if (bombButton[i][j].isBomb != true) {
if ((i - 1 >= 0) && (j - 1 >= 0)) {
if (bombButton[i - 1][j - 1].isBomb == true) {
count += 1; // 检测左上方空格是否是地雷
}
}
if ((i - 1 >= 0)) {
if (bombButton[i - 1][j].isBomb == true) {
count += 1; // 检测上方空格是否为地雷
}
}
if ((i - 1 >= 0)
&& (j + 1 <= (int) Math.sqrt(BlockNum) - 1)) {
if (bombButton[i - 1][j + 1].isBomb == true) {
count += 1; // 检测右上方是否为地雷
}
}
if ((j - 1 >= 0)) {
if (bombButton[i][j - 1].isBomb == true) {
count += 1; // 检测左边是否为地雷
}
}
if ((i >= 0) && (j + 1 <= (int) Math.sqrt(BlockNum) - 1)) {
if (bombButton[i][j + 1].isBomb == true) {
count += 1; // 右边
}
}
if ((j - 1 >= 0)
&& (i + 1 <= (int) Math.sqrt(BlockNum) - 1)) {
if (bombButton[i + 1][j - 1].isBomb == true) {
count += 1; // 左下
}
}
if ((i + 1 <= (int) Math.sqrt(BlockNum) - 1)) {
if (bombButton[i + 1][j].isBomb == true) {
count += 1; // 下
}
}
if ((j + 1 <= (int) Math.sqrt(BlockNum) - 1)
&& (i + 1 <= Math.sqrt(BlockNum) - 1)) {
if (bombButton[i + 1][j + 1].isBomb == true) {
count += 1; // 右下
}
}
bombButton[i][j].BombRoundCount = count;
}
}
}
}
/** 当选中的位置为空,则翻开周围的地图 **/
public void isNull(Bomb[][] bombButton, Bomb ClickecButton) {
int i, j;
i = ClickecButton.num_x;
j = ClickecButton.num_y;
if (ClickecButton.isBomb == true) {
} else {
if ((i - 1 >= 0) && (j - 1 >= 0)) { // 检测左上方空格是否是空
if (bombButton[i - 1][j - 1].isBomb == false
&& bombButton[i - 1][j - 1].isClicked == false
&& bombButton[i - 1][j - 1].isRight == false) {
bombButton[i - 1][j - 1]
.setText((bombButton[i - 1][j - 1].BombRoundCount)
+ "");
bombButton[i - 1][j - 1].setEnabled(false);
bombButton[i - 1][j - 1].isClicked = true;
}
}
if ((i - 1 >= 0)) { // 检测上方空格是否为空
if (bombButton[i - 1][j].isBomb == false
&& bombButton[i - 1][j].isClicked == false
&& bombButton[i - 1][j].isRight == false) {
bombButton[i - 1][j]
.setText((bombButton[i - 1][j].BombRoundCount) + "");
bombButton[i - 1][j].setEnabled(false);
bombButton[i - 1][j].isClicked = true;
}
}
if ((i - 1 >= 0) && (j + 1 <= ((int) Math.sqrt(BlockNum) - 1))) { // 检测右上方是否为空
if (bombButton[i - 1][j + 1].isBomb == false
&& bombButton[i - 1][j + 1].isClicked == false
&& bombButton[i - 1][j + 1].isRight == false) {
bombButton[i - 1][j + 1]
.setText((bombButton[i - 1][j + 1].BombRoundCount)
+ "");
bombButton[i - 1][j + 1].setEnabled(false);
bombButton[i - 1][j + 1].isClicked = true;
}
}
if ((j - 1 >= 0)) { // 检测左边是否为空
if (bombButton[i][j - 1].isBomb == false
&& bombButton[i][j - 1].isClicked == false
&& bombButton[i][j - 1].isRight == false) {
bombButton[i][j - 1]
.setText((bombButton[i][j - 1].BombRoundCount) + "");
bombButton[i][j - 1].setEnabled(false);
bombButton[i][j - 1].isClicked = true;
}
}
if ((i >= 0) && (j + 1 <= ((int) Math.sqrt(BlockNum) - 1))) { // 检测右边空格是否是空
if (bombButton[i][j + 1].isBomb == false
&& bombButton[i][j + 1].isClicked == false
&& bombButton[i][j + 1].isRight == false) {
bombButton[i][j + 1]
.setText((bombButton[i][j + 1].BombRoundCount) + "");
bombButton[i][j + 1].setEnabled(false);
bombButton[i][j + 1].isClicked = true;
}
}
if ((j - 1 >= 0) && (i + 1 <= ((int) Math.sqrt(BlockNum) - 1))) { // 检测左下空格是否是空
if (bombButton[i + 1][j - 1].isBomb == false
&& bombButton[i + 1][j - 1].isClicked == false
&& bombButton[i + 1][j - 1].isRight == false) {
bombButton[i + 1][j - 1]
.setText((bombButton[i + 1][j - 1].BombRoundCount)
+ "");
bombButton[i + 1][j - 1].setEnabled(false);
bombButton[i + 1][j - 1].isClicked = true;
}
}
if ((i + 1 <= ((int) Math.sqrt(BlockNum) - 1))) { // 检测下边空格是否是空
if (bombButton[i + 1][j].isBomb == false
&& bombButton[i + 1][j].isClicked == false
&& bombButton[i + 1][j].isRight == false) {
bombButton[i + 1][j]
.setText((bombButton[i + 1][j].BombRoundCount) + "");
bombButton[i + 1][j].setEnabled(false);
bombButton[i + 1][j].isClicked = true;
}
}
if ((j + 1 <= ((int) Math.sqrt(BlockNum) - 1))
&& (i + 1 <= ((int) Math.sqrt(BlockNum) - 1))) { // 检测右下边空格是否是空
if (bombButton[i + 1][j + 1].isBomb == false
&& bombButton[i + 1][j + 1].isClicked == false
&& bombButton[i + 1][j + 1].isRight == false) {
bombButton[i + 1][j + 1]
.setText((bombButton[i + 1][j + 1].BombRoundCount)
+ "");
bombButton[i + 1][j + 1].setEnabled(false);
bombButton[i + 1][j + 1].isClicked = true;
}
}
if ((i - 1 >= 0) && (j - 1 >= 0))// 检测左上
isNull(bombButton, bombButton[i - 1][j - 1]);
if ((i - 1 >= 0))
isNull(bombButton, bombButton[i - 1][j]);// 检测上方
if ((i - 1 >= 0) && (j + 1 <= (int) Math.sqrt(BlockNum) - 1))
isNull(bombButton, bombButton[i - 1][j + 1]);// 检测右上
if ((j - 1 >= 0))
isNull(bombButton, bombButton[i][j - 1]);// 检测左边
if ((i >= 0) && (j + 1 <= ((int) Math.sqrt(BlockNum) - 1)))
isNull(bombButton, bombButton[i][j + 1]);// 检测右边
if ((j - 1 >= 0) && (i + 1 <= ((int) Math.sqrt(BlockNum) - 1)))
isNull(bombButton, bombButton[i + 1][j - 1]); // 检测左下
if ((i + 1 <= ((int) Math.sqrt(BlockNum) - 1))) // 检测下
isNull(bombButton, bombButton[i + 1][j]);
if ((j + 1 <= ((int) Math.sqrt(BlockNum) - 1))
&& (i + 1 <= ((int) Math.sqrt(BlockNum) - 1))) // 检测右下
isNull(bombButton, bombButton[i + 1][j + 1]);
}
}
public void actionPerformed(ActionEvent e) {
CountRoundBomb();
if (((Bomb) e.getSource()).isBomb == false
&& ((Bomb) e.getSource()).isClicked == false) {
((Bomb) e.getSource())
.setText((((Bomb) e.getSource()).BombRoundCount) + "");
((Bomb) e.getSource()).isClicked = true;
((Bomb) e.getSource()).setIcon(null);
((Bomb) e.getSource()).setEnabled(false);
if ((((Bomb) e.getSource()).BombRoundCount) == 0)
isNull(bombButton, (Bomb) e.getSource());
isWin();
} else if (((Bomb) e.getSource()).isBomb == true) {
for (int i = 0; i < (int) Math.sqrt(BlockNum); i++)
for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {
if (bombButton[i][j].isBomb == true)
bombButton[i][j].setIcon(icon_bomb);
}
((Bomb) e.getSource()).setIcon(icon_bomb_big);
new JOptionPane();
JOptionPane.showMessageDialog(this, "你踩到地雷了,按确定重来", "你踩到地雷了", 2);
replay();
}
}
public void mouseClicked(MouseEvent e) {
Bomb bombSource = (Bomb) e.getSource();
boolean right = SwingUtilities.isRightMouseButton(e);
if ((right == true) && (bombSource.isClicked == false)) {
bombSource.BombFlag = (bombSource.BombFlag + 1) % 3;
if (bombSource.BombFlag == 1) {
if (BombNum > 0 && bombSource.isRight == false) {
bombSource.setIcon(icon_flag);
bombSource.isRight = true;
BombNum--;
}
isWin();
nowBomb.setText("当前雷数" + " " + BombNum + "");
} else if (bombSource.BombFlag == 2) {
if ((BombNum != 0)
|| (BombNum == 0 && (bombSource.getIcon() == icon_flag)))
BombNum++;
bombSource.setIcon(icon_question);
nowBomb.setText("当前雷数" + " " + BombNum + "");
} else if (bombSource.BombFlag == 0) {
bombSource.setIcon(null);
bombSource.isRight = false;
}
}
}
public void mouseEntered(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
}
/* 主类 *
public class MineSquare {
public static void main(String args[]) {
(new MainBomb()).setVisible(true);
}
}
最后调试结果如下图:
项目开发时间
步骤 |
耗时(h) |
百分比 |
需求分析 |
1 |
18% |
设计 |
2 |
36% |
代码实现 |
1 |
18% |
测试 |
1 |
18% |
分析总结 |
0.5 |
10%
|
实验总结
在本次的实验中在命令端输入git status总是提示不存在,通过百度的出要先建立仓库需要输入git init;当输入vi HelloWorld.java指令时出显文本编辑刚开始不知道怎么输入,最后通过esc 、i、及wq将问题解决。在本次的试验中小软件的编写存在问题,在编程方面还需要提高自己。在这三次的实验中明显能感觉到和其他同学存在的差距,在以后的学习中应该多学、多问、多思。