zoukankan      html  css  js  c++  java
  • 20145231《Java程序设计》第三次实验报告

    实验三 敏捷开发与XP实现

    实验内容

    1. XP基础

    2. XP核心实践

    3. 相关工具

    实验要求

    1. 了解敏捷开发的基本方法以及XP软件开发的相关准则;了解代码编写的标准和原则;体会结对编程的好处;

    2. 实践体会版本控制的方法及优势;

    3. 利用重构完善代码;

    4. 通过结对方式编写软件;

    实验步骤

    (一)敏捷开发与XP

    敏捷开发(Agile Development)是一种以人为核心、迭代、循序渐进的开发方法

    软件工程=开发流程+工具 软件=程序+软件工程 软件企业=软件+商业模式

    极限编程(eXtreme Programming,XP)是 是一种全新而快捷的软件开发方法

    •XP是以开发符合客户需要的软件为目标而产生的一种方法论;

    •XP是一种以实践为基础的软件工程过程和思想;

    •XP认为代码质量的重要程度超出人们一般所认为的程度;

    •XP特别适合于小型的有责任心的、自觉自励的团队开发需求不确定或者迅速变化的软件;

    XP的法则:快速反馈、假设简单性、递增更改、提倡更改、优质工作;

    XP的活动:编码、测试、倾听、设计;

    XP实践:项目成员用户成功执行XP活动的技术通过XP实践来呈现;

    (二)编码标准

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

    •代码标准中很重要的一项是如何给包、类、变量、方法等标识符命名,Java中的一般的命名规则有:

    要体现各自的含义

    包、类、变量用名词

    方法名用动宾

    包名全部小写,如:io,awt

    类名第一个字母要大写,如:HelloWorldApp

    变量名第一个字母要小写,如:userName

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

    目前IDEA中已经能自动修改缩进格式如图:

    (三)结对编程

    结对编程是XP中的重要实践

    •在合作中进行程序开发,在两种角色之间相互转换,培养团队精神。

    (四)版本控制

    •版本控制的好处:

    1. 版本控制提供项目级的 undo(撤销) 功能:这意味着你的项目不会因为操作失误而丢失;

    2. 版本控制允许多人在同一代码上工作, 只要遵守一定的控制原则就行:不会因代码覆盖而导致前人修改代码无效;

    3. 版本控制系统保存了过去所作的修改的历史记录:可以知道谁修改了代码,查出原因;

    版本控制系统还支持在主线上开发的同时发布多个软件版本:不必在软件发布时停下或冻结代码;

    1. 版本控制也是项目级的时间机器,你可以选择任何一个时间, 精确地查看项目在当时的情况:是重现以前某个有问题的发布版本的基础;

    •流行的版本控制工具有CVS,SVN,Git等;

    •使用Git进行版本控制的实践(包括结对编程中代码的提交与下载)

    不下载安装git到本地就只能使用最没有效率的复制粘贴。

    按照代码托管步骤进行:

    1. 下载安装gitAPP到本地,打开命令行模式,输入git指令,即可使用,如图:

    1. 命令行模式下给git配置自己的用户名和邮箱,如图:

    1. 配置ssh公钥步骤,如图:

    配置成功:

    1. 写好需要上传的项目:即Hello.java

    2. 准备工作完成,开始托管代码:

    与git@osc建立连接:

    找到需要上传项目的位置并Git Bush Here一下,在命令窗口中第二次建立连接(不再需要输入用户名和密码):

    输入相应指令如图:

    git init git add git add. git commit git commit -m

    push失败

    在IDEA中配置并使用git更加方便快捷,如图:

    push成功并与结对伙伴相互尝试下载:

    (五)重构

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

    •对重构功能的应用与实践

    重命名

    代码的封装

    解决代码重复

    •重构的好处(软件的修改与维护)

    增加新功能;

    原有功能有BUG;

    改善原有程序的结构;

    优化原有系统的性能 。

    •哪些地方需要重构

    最不能出现的就是代码的重复 Duplicated Code

    最单纯的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与相应的重构手法如下表所示:

    (六)实践项目

    结对伙伴网址:https://home.cnblogs.com/u/20145210ysy/

    贡献均等,重构过程、TDD等,抱歉两天的时间内实在无法完成能力有限。

    代码如下:

    package resource;
    
    import java.awt.*;
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class MainClass extends JFrame {
        ControlSnake control;
    
        Toolkit kit;
    
        Dimension dimen;
    
        public static void main(String[] args) {
            new MainClass("my snake");
        }
    
        public MainClass(String s) {
            super(s);
            control = new ControlSnake();
            control.setFocusable(true);
            kit = Toolkit.getDefaultToolkit();
            dimen = kit.getScreenSize();
    
            add(control);
            setLayout(new BorderLayout());
            setLocation(dimen.width / 3, dimen.height / 3);// dimen.width/3,dimen.height/3
            setSize(FWIDTH, FHEIGHT);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setResizable(false);
            setVisible(true);
        }
    
        public static final int FWIDTH = 315;
    
        public static final int FHEIGHT = 380;
    }
    
    
    package resource;
    
    import java.util.*;
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.Timer;
    import java.util.Random;
    
    @SuppressWarnings("serial")
    public class ControlSnake extends JPanel implements ActionListener {
        Random rand;
    
        ArrayList<Point> list, listBody;
    
        String str, str1;
    
        static boolean key;
    
        int x, y, dx, dy, fx, fy, flag;
    
        int snakeBody;
    
        int speed;
    
        public ControlSnake() {
            snakeBody = 1;
    
            str = "上下左右方向键控制 P键暂停...";
            str1 = "现在的长度为:" + snakeBody;
            key = true;
            flag = 1;
    
            speed = 700;
            rand = new Random();
            list = new ArrayList<Point>();
            listBody = new ArrayList<Point>();
    
            x = 5;
            y = 5;
            list.add(new Point(x, y));
            listBody.add(list.get(0));
    
            dx = 10;
            dy = 0;
    
            fx = rand.nextInt(30) * 10 + 5;// 2
            fy = rand.nextInt(30) * 10 + 5;// 2
    
            setBackground(Color.WHITE);
            setSize(new Dimension(318, 380));
    
            final Timer time = new Timer(speed, this);
            time.start();
    
            addKeyListener(new KeyAdapter() {
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() == 37) {
                        dx = -10;
                        dy = 0;
                    } else if (e.getKeyCode() == 38) {
                        dx = 0;
                        dy = -10;
                    } else if (e.getKeyCode() == 39) {
                        dx = 10;
                        dy = 0;
                    } else if (e.getKeyCode() == 40) {
                        dx = 0;
                        dy = 10;
                    } else if (e.getKeyCode() == 80) {
                        if (flag % 2 == 1) {
                            time.stop();
                        }
                        if (flag % 2 == 0) {
                            time.start();
                        }
                        flag++;
                    }
                }
            });
    
        }
    
        public void paint(Graphics g) {
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, 400, 400);
            g.setColor(Color.DARK_GRAY);
            g.drawLine(3, 3, 305, 3);
            g.drawLine(3, 3, 3, 305);
            g.drawLine(305, 3, 305, 305);
            g.drawLine(3, 305, 305, 305);
            g.setColor(Color.PINK);
    
            for (int i = 0; i < listBody.size(); i++) {
                g.fillRect(listBody.get(i).x, listBody.get(i).y, 9, 9);
            }
            g.fillRect(x, y, 9, 9);
            g.setColor(Color.ORANGE);
            g.fillRect(fx, fy, 9, 9);
    
            g.setColor(Color.DARK_GRAY);
            str1 = "现在的长度为:" + snakeBody;
            g.drawString(str, 10, 320);
            g.drawString(str1, 10, 335);
        }
    
        public void actionPerformed(ActionEvent e) {
            x += dx;
            y += dy;
            if (makeOut() == false) {
                JOptionPane.showMessageDialog(null, "重新开始......");
    
                speed = 700;
    
                snakeBody = 1;
    
                x = 5;
                y = 5;
    
                list.clear();
                list.add(new Point(x, y));
                listBody.clear();
                listBody.add(list.get(0));
    
                dx = 10;
                dy = 0;
    
            }
            addPoint(x, y);
            if (x == fx && y == fy) {
                speed = (int) (speed * 0.8);// 速度增加参数
                if (speed < 200) {
                    speed = 100;
                }
                fx = rand.nextInt(30) * 10 + 5;// 2
                fy = rand.nextInt(30) * 10 + 5;// 2
                snakeBody++;// 2
            } // 2
            repaint();
        }
    
        public void addPoint(int xx, int yy) {
            // 动态的记录最新发生的50步以内的移动过的坐标
            // 并画出最新的snakeBody
            if (list.size() < 100) {// 蛇身长度最长为100
                list.add(new Point(xx, yy));
            } else {
                list.remove(0);
                list.add(new Point(xx, yy));
            }
            if (snakeBody == 1) {
                listBody.remove(0);
                listBody.add(0, list.get(list.size() - 1));
            } else {
                listBody.clear();
                if (list.size() < snakeBody) {
                    for (int i = list.size() - 1; i > 0; i--) {
                        listBody.add(list.get(i));
                    }
                } else {
                    for (int i = list.size() - 1; listBody.size() < snakeBody; i--) {
                        listBody.add(list.get(i));
                    }
                }
            }
        }
    
        public boolean makeOut() {
            if ((x < 3 || y < 3) || (x > 305 || y > 305)) {
                return false;
            }
            for (int i = 0; i < listBody.size() - 1; i++) {
                for (int j = i + 1; j < listBody.size(); j++) {
                    if (listBody.get(i).equals(listBody.get(j))) {
                        return false;
                    }
                }
            }
            return true;
        }
    }
    
    

    运行结果如图:

    遇到的问题及解决方法

    使用cmd命令行一开始托管代码失败了,经过在IDEA中设置的最后一步输入账号和密码时,发现修改过用户名,所以在更正了用户名后托管成功。

    在实践项目中设计思路有一定问题,大体参照了前面同学的成果并尝试理解、改进。

    比起用git add、git commit、git push的节奏托管代码,我现在还是比较倾向于简单的复制粘贴,可能是刚开始还不太适应,希望以后熟悉了它能真正带来便利。

    Personal Software Process Time

    步骤 耗时 百分比
    需求分析 3hour 9.8%
    设计代码实现 10hours 82%
    测试 2hours 6.6%
    分析总结 0.5hour 1.6%
  • 相关阅读:
    Axiom3D:资源引用与加载基本流程.
    实践:C++平台迁移以及如何用C#做C++包装层
    Axiom3D:Buffer漫谈
    CSS: hover选择器的使用
    TTS 语音修复 ,缺少文件的,没注册类的
    sqlserver 查找某个字段在哪张表里
    Excel 表格查找重复数据,去重复统计
    C# HttpWebResponse WebClient 基础连接已经关闭: 发送时发生错误.
    C# 控件置于最顶层、最底层
    C# 线程 正确使用Thread.Join()停止方式
  • 原文地址:https://www.cnblogs.com/xzh20145231/p/5428540.html
Copyright © 2011-2022 走看看