标签:
北京电子科技学院
实 验 报 告
课程:移动平台应用开发实践 班级:201592 姓名:苏泽楠 学号:20159207
成绩: 指导教师:娄嘉鹏 实验日期:2015.10.15
实验密级: 预习程度: 实验时间:
仪器组次: 必修/选修:选修 实验序号:3
实验名称: 敏捷开发与XP实践
实验内容
1. XP基础
2. XP核心实践
3. 相关工具
实验步骤
(一)敏捷开发与XP
软件工程是把系统的、有序的、可量化的方法应用到软件的开发、运营和维护上的过程。软件工程包括下列领域:软件需求分析、软件设计、软件构建、软件测试和软件维护。 人们在开发、运营、维护软件的过程中有很多技术、做法、习惯和思想体系。软件工程把这些相关的技术和过程统一到一个体系中,叫“软件开发流程”。软件开发流程的目的是为了提高软件开发、运营、维护的效率,并提高软件的质量、用户满意度、可靠性和软件的可维护性。 光有各种流程的思想是不够的,我们还要有一系列的工具来保证这些思想能够在实践中有效率地运作。软件开发很重要的一点不是看你能对多少理论讲的头头是道,还要看你对相关工具应用的如何,比如Java中单元测试要和JUnit的应用结合起来,建模要和Umbrello或StarUML的应用结合起来。编程学习是一个习而学的过程。 一个常见的公式是:软件工程=开发流程+工具 邹欣老师给出的两个公式:软件=程序+软件工程和软件企业=软件+商业模式 开发流程大家可以参考学习邹欣老师的软件团队和开发流程。常见的开发流程有:
敏捷开发(Agile Development)是一种以人为核心、迭代、循序渐进的开发方法。“敏捷流程”是一系列价值观和方法论的集合。从2001年开始,一些软件界的专家开始倡导“敏捷”的价值观和流程,他们肯定了流行做法的价值,但是强调敏捷的做法更能带来价值。
其中,极限编程(eXtreme Programming,XP)是
是一种全新而快捷的软件开发方法。XP团队使用现场客户、特殊计划方法和持续测试来提供快速的反馈和全面的交流:
XP软件开发是什么样的通过 XP准则来表达:
一项实践在XP环境中成功使用的依据通过XP的法则呈现,包括:快速反馈、假设简单性、递增更改、提倡更改、优质工作。
XP软件开发的基石是XP的活动,包括:编码、测试、倾听、设计。
(二)编码标准
编写代码一个重要的认识是“程序大多时候是给人看的”,编程标准使代码更容易阅读和理解,甚至可以保证其中的错误更少。编程标准包含:具有说明性的名字、清晰的表达式、直截了当的控制流、可读的代码和注释,以及在追求这些内容时一致地使用某些规则和惯用法的重要性。
编码标准中的版式就是一个很好的例子,版式虽然不会影响程序的功能,但会影响可读性。程序的版式追求清晰、美观,是程序风格的重要因素。
三)结对编程
结对编程是XP中的重要实践。在结对编程模式下,一对程序员肩并肩、平等地、互补地进行开发工作。他们并排坐在一台电脑前,面对同一个显示器,使用同一个键盘、同一个鼠标一起工作。他们一起分析,一起设计,一起写测试用例,一起编码,一起做单元测试,一起做集成测试,一起写文档等。 结对编程中有两个角色:
如何结对编程,为何要结对编程,大家参考一下结对编程和两人合作,重点是:
团队精神是好多地方都强调的一个精神,最小的团队就是一对一的二人团队了,培养团队精神从结对编程开始吧。社会生活中人与人相处最重要的是诚信,有同理心,互利。结对编程中大家会出现分歧,如何更有效地合作要做到对事不对人,掌握这些是可以终生受益的。
(四)版本控制
XP的集体所有制意味着每个人都对所有的代码负责;这一点,反过来又意味着每个人都可以更改代码的任意部分。结对编程对这一实践贡献良多:借由在不同的结对中工作,所有的程序员都能看到完全的代码。集体所有制的一个主要优势是提升了开发程序的速度,因为一旦代码中出现错误,任何程序员都能修正它。 这意味着代码要放到一个大家都能方便获取的地方,我们叫代码仓库。这引出另外一个话题叫版本控制(Version Control)。
不论是对于团队还是个体,版本控制都提供了很多好处。
(五)重构
我们先看看重构的概念:
重构(Refactor),就是在不改变软件外部行为的基础上,改变软件内部的结构,使其更加易于阅读、易于维护和易于变更。
重构中一个非常关键的前提就是“不改变软件外部行为”,它保证了我们在重构原有系统的同时,不会为原系统带来新的BUG,以确保重构的安全。如何保证不改变软件外部行为?重构后的代码要能通过单元测试。如何使其更加易于阅读、易于维护和易于变更 ?设计模式给出了重构的目标。
(六)实验过程截图:
1,Eclipse菜单中的source->Format 或用快捷键Ctrl+Shift+F就可以按Eclipse规定的规范缩进
2、重构
重构的一个具体实例:
3、结对编程
游戏名称:玩转五子棋
队友:20159215田仁贵
博客:http://www.cnblogs.com/20159215trg/
我的主要任务是:编写伪代码、完善代码、添加注释、TDD测试
/*
五子棋主框架,程序启动
*/
public class StartChessJFrame extends JFrame {
private ChessBoard chessBoard;
private JPanel toolbar;
private JButton startButton, backButton, exitButton;
private JMenuBar menuBar;
private JMenu sysMenu;
private JMenuItem startMenuItem, exitMenuItem, backMenuItem;
// 重新开始,退出,和悔棋菜单项
public StartChessJFrame() {
setTitle("单机版五子棋");// 设置标题
chessBoard = new ChessBoard();
Container contentPane = getContentPane();
contentPane.add(chessBoard);
chessBoard.setOpaque(true);
// 创建和添加菜单
menuBar = new JMenuBar();// 初始化菜单栏
sysMenu = new JMenu("系统");// 初始化菜单
// 初始化菜单项
startMenuItem = new JMenuItem("重新开始");
exitMenuItem = new JMenuItem("退出");
backMenuItem = new JMenuItem("悔棋");
// 将三个菜单项添加到菜单上
sysMenu.add(startMenuItem);
sysMenu.add(exitMenuItem);
sysMenu.add(backMenuItem);
// 初始化按钮事件监听器内部类
MyItemListener lis = new MyItemListener();
// 将三个菜单注册到事件监听器上
this.startMenuItem.addActionListener(lis);
backMenuItem.addActionListener(lis);
exitMenuItem.addActionListener(lis);
menuBar.add(sysMenu);// 将系统菜单添加到菜单栏上
setJMenuBar(menuBar);// 将menuBar设置为菜单栏
toolbar = new JPanel();// 工具面板实例化
// 三个按钮初始化
startButton = new JButton("重新开始");
exitButton = new JButton("退出");
backButton = new JButton("悔棋");
// 将工具面板按钮用FlowLayout布局
toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));
// 将三个按钮添加到工具面板
toolbar.add(startButton);
toolbar.add(exitButton);
toolbar.add(backButton);
// 将三个按钮注册监听事件
startButton.addActionListener(lis);
exitButton.addActionListener(lis);
backButton.addActionListener(lis);
// 将工具面板布局到界面下方
add(toolbar, BorderLayout.SOUTH);
add(chessBoard);// 将面板对象添加到窗体上
// 设置界面关闭事件
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// setSize(800,800);
pack();// 自适应大小
}
private class MyItemListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();// 获得事件源
if (obj == StartChessJFrame.this.startMenuItem
|| obj == startButton) {
// 重新开始
// JFiveFrame.this内部类引用外部类
System.out.println("重新开始");
chessBoard.restartGame();
} else if (obj == exitMenuItem || obj == exitButton)
System.exit(0);
else if (obj == backMenuItem || obj == backButton) {
System.out.println("悔棋...");
chessBoard.goback();
}
}
}
public static void main(String[] args) {
StartChessJFrame f = new StartChessJFrame();// 创建主框架
f.setVisible(true);// 显示主框架
}
}
/**
* 棋子类
*/
public class Point {
private int x;// 棋盘中的x索引
private int y;// 棋盘中的y索引
private Color color;// 颜色
public static final int DIAMETER = 30;// 直径
public Point(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getX() {// 拿到棋盘中x的索引
return x;
}
public int getY() {
return y;
}
public Color getColor() {// 获得棋子的颜色
return color;
}
}
/**
* 五子棋--棋盘类
*/
public class ChessBoard extends JPanel implements MouseListener {
public static final int MARGIN = 30;// 边距
public static final int GRID_SPAN = 35;// 网格间距
public static final int ROWS = 15;// 棋盘行数
public static final int COLS = 15;// 棋盘列数
Point[] chessList = new Point[(ROWS + 1) * (COLS + 1)];// 初始每个数组元素为null
boolean isBlack = true;// 默认开始是黑棋先
boolean gameOver = false;// 游戏是否结束
int chessCount;// 当前棋盘棋子的个数
int xIndex, yIndex;// 当前刚下棋子的索引
Image img;
Image shadows;
Color colortemp;
public ChessBoard() {
setBackground(Color.orange);// 设置背景色为橘黄色
img = Toolkit.getDefaultToolkit().getImage("board.jpg");
shadows = Toolkit.getDefaultToolkit().getImage("shadows.jpg");
addMouseListener(this);
addMouseMotionListener(new MouseMotionListener() {
public void mouseDragged(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
// 边距 网格间距
int x1 = (e.getX() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;
// 将鼠标点击的坐标位置转成网格索引
int y1 = (e.getY() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;
// 游戏已经结束不能下
// 落在棋盘外不能下
// x,y位置已经有棋子存在,不能下
if (x1 < 0 || x1 > ROWS || y1 < 0 || y1 > COLS || gameOver
|| findChess(x1, y1))
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
// 设置成默认状态
else
setCursor(new Cursor(Cursor.HAND_CURSOR));
}
});
}
// 绘制
public void paintComponent(Graphics g) {
super.paintComponent(g);// 画棋盘
int imgWidth = img.getWidth(this);
int imgHeight = img.getHeight(this);// 获得图片的宽度与高度
int FWidth = getWidth();
int FHeight = getHeight();// 获得窗口的宽度与高度
int x = (FWidth - imgWidth) / 2;
int y = (FHeight - imgHeight) / 2;
g.drawImage(img, x, y, null);
for (int i = 0; i <= ROWS; i++) {// 画横线
g.drawLine(MARGIN, MARGIN + i * GRID_SPAN, MARGIN + COLS
* GRID_SPAN, MARGIN + i * GRID_SPAN);
}
for (int i = 0; i <= COLS; i++) {// 画竖线
g.drawLine(MARGIN + i * GRID_SPAN, MARGIN, MARGIN + i * GRID_SPAN,
MARGIN + ROWS * GRID_SPAN);
}
// 画棋子
for (int i = 0; i < chessCount; i++) {
// 网格交叉点x,y坐标
int xPos = chessList[i].getY() * GRID_SPAN + MARGIN;
int yPos = chessList[i].getX() * GRID_SPAN + MARGIN;
g.setColor(chessList[i].getColor());// 设置颜色
// g.fillOval(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2,
// Point.DIAMETER, Point.DIAMETER);
// g.drawImage(shadows, xPos-Point.DIAMETER/2,
// yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER, null);
colortemp = chessList[i].getColor();
if (colortemp == Color.black) {
RadialGradientPaint paint = new RadialGradientPaint(xPos
- Point.DIAMETER / 2 + 25, yPos - Point.DIAMETER / 2
+ 10, 20, new float[] { 0f, 1f }, new Color[] {
Color.WHITE, Color.BLACK });
((Graphics2D) g).setPaint(paint);
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
} else if (colortemp == Color.white) {
RadialGradientPaint paint = new RadialGradientPaint(xPos
- Point.DIAMETER / 2 + 25, yPos - Point.DIAMETER / 2
+ 10, 70, new float[] { 0f, 1f }, new Color[] {
Color.WHITE, Color.BLACK });
((Graphics2D) g).setPaint(paint);
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
}
Ellipse2D e = new Ellipse2D.Float(xPos - Point.DIAMETER / 2, yPos
- Point.DIAMETER / 2, 34, 35);
((Graphics2D) g).fill(e);
// 标记最后一个棋子的红矩形框
if (i == chessCount - 1) {// 如果是最后一个棋子
g.setColor(Color.red);
g.drawRect(xPos - Point.DIAMETER / 2,
yPos - Point.DIAMETER / 2, 34, 35);
}
}
}
public void mousePressed(MouseEvent e) {// 鼠标在组件上按下时调用
// 游戏结束时,不再能下
if (gameOver)
return;
String colorName = isBlack ? "黑棋" : "白棋";
// 将鼠标点击的坐标位置转换成网格索引
xIndex = (e.getX() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;
yIndex = (e.getY() - MARGIN + GRID_SPAN / 2) / GRID_SPAN;
// 落在棋盘外不能下
if (xIndex < 0 || xIndex > ROWS || yIndex < 0 || yIndex > COLS)
return;
// 如果x,y位置已经有棋子存在,不能下
if (findChess(xIndex, yIndex))
return;
// 可以进行时的处理
Point ch = new Point(xIndex, yIndex, isBlack ? Color.black
: Color.white);
chessList[chessCount++] = ch;
repaint();// 通知系统重新绘制
// 如果胜出则给出提示信息,不能继续下棋
if (isWin()) {
String msg = String.format("恭喜,%s赢了!", colorName);
JOptionPane.showMessageDialog(this, msg);
gameOver = true;
}
isBlack = !isBlack;
}
// 覆盖mouseListener的方法
public void mouseClicked(MouseEvent e) {
// 鼠标按键在组件上单击时调用
}
public void mouseEntered(MouseEvent e) {
// 鼠标进入到组件上时调用
}
public void mouseExited(MouseEvent e) {
// 鼠标离开组件时调用
}
public void mouseReleased(MouseEvent e) {
// 鼠标按钮在组件上释放时调用
}
// 在棋子数组中查找是否有索引为x,y的棋子存在
private boolean findChess(int x, int y) {
for (Point c : chessList) {
if (c != null && c.getX() == x && c.getY() == y)
return true;
}
return false;
}
private boolean isWin() {
int continueCount = 1;// 连续棋子的个数
// 横向向西寻找
for (int x = xIndex - 1; x >= 0; x--) {
Color c = isBlack ? Color.black : Color.white;
if (getChess(x, yIndex, c) != null) {
continueCount++;
} else
break;
}
// 横向向东寻找
for (int x = xIndex + 1; x <= COLS; x++) {
Color c = isBlack ? Color.black : Color.white;
if (getChess(x, yIndex, c) != null) {
continueCount++;
} else
break;
}
if (continueCount >= 5) {
return true;
} else
continueCount = 1;
// 继续另一种搜索纵向
// 向上搜索
for (int y = yIndex - 1; y >= 0; y--) {
Color c = isBlack ? Color.black : Color.white;
if (getChess(xIndex, y, c) != null) {
continueCount++;
} else
break;
}
// 纵向向下寻找
for (int y = yIndex + 1; y <= ROWS; y++) {
Color c = isBlack ? Color.black : Color.white;
if (getChess(xIndex, y, c) != null)
continueCount++;
else
break;
}
if (continueCount >= 5)
return true;
else
continueCount = 1;
// 继续另一种情况的搜索:斜向
// 东北寻找
for (int x = xIndex + 1, y = yIndex - 1; y >= 0 && x <= COLS; x++, y--) {
Color c = isBlack ? Color.black : Color.white;
if (getChess(x, y, c) != null) {
continueCount++;
} else
break;
}
// 西南寻找
for (int x = xIndex - 1, y = yIndex + 1; x >= 0 && y <= ROWS; x--, y++) {
Color c = isBlack ? Color.black : Color.white;
if (getChess(x, y, c) != null) {
continueCount++;
} else
break;
}
if (continueCount >= 5)
return true;
else
continueCount = 1;
// 继续另一种情况的搜索:斜向
// 西北寻找
for (int x = xIndex - 1, y = yIndex - 1; x >= 0 && y >= 0; x--, y--) {
Color c = isBlack ? Color.black : Color.white;
if (getChess(x, y, c) != null)
continueCount++;
else
break;
}
// 东南寻找
for (int x = xIndex + 1, y = yIndex + 1; x <= COLS && y <= ROWS; x++, y++) {
Color c = isBlack ? Color.black : Color.white;
if (getChess(x, y, c) != null)
continueCount++;
else
break;
}
if (continueCount >= 5)
return true;
else
continueCount = 1;
return false;
}
private Point getChess(int xIndex, int yIndex, Color color) {
for (Point p : chessList) {
if (p != null && p.getX() == xIndex && p.getY() == yIndex
&& p.getColor() == color)
return p;
}
return null;
}
public void restartGame() {
// 清除棋子
for (int i = 0; i < chessList.length; i++) {
chessList[i] = null;
}
// 恢复游戏相关的变量值
isBlack = true;
gameOver = false; // 游戏是否结束
chessCount = 0; // 当前棋盘棋子个数
repaint();
}
// 悔棋
public void goback() {
if (chessCount == 0)
return;
chessList[chessCount - 1] = null;
chessCount--;
if (chessCount > 0) {
xIndex = chessList[chessCount - 1].getX();
yIndex = chessList[chessCount - 1].getY();
}
isBlack = !isBlack;
repaint();
}
// 矩形Dimension
public Dimension getPreferredSize() {
return new Dimension(MARGIN * 2 + GRID_SPAN * COLS, MARGIN * 2
+ GRID_SPAN * ROWS);
}
}
实验时间
步骤 |
耗时 |
百分比 |
需求分析 |
50min |
27% |
设计 |
40min |
21.6% |
代码实现 |
50min |
27% |
测试 |
45min |
24.3% |
分析总结 |
40min |
21.6% |
实验总结
通过这次实验我发现自己的编程能力不足,主要是基础知识薄弱,在编写StudentTest类时,不会使用toString()方法,我认真研究了toString()方法后,还是没有解决,最后换了个思路将代码重新查了一遍后发现原来是一个“}”的问题,使得static显示错误,我的查错能力有待提高,很多错误都是很简单却很难发现的,在今后的学习中要着重提高这方面的能力。
标签:
原文地址:http://www.cnblogs.com/20159207szn/p/4889266.html