北京電子科技學院(BESTI)php
實 驗 報 告html
課程:Java 班級: 1352 姓名:談愈敏 學號:20135220java
成績: 指導教師:婁嘉鵬 實驗日期:2015.5.8git
實驗密級: 預習程度: 實驗時間:15:30~18:00程序員
儀器組次:20 必修/選修:選修 實驗序號:02github
實驗名稱:敏捷開發與XP實踐 算法
實驗儀器:express
名稱編程 |
型號設計模式 |
數量 |
計算機 |
lenovo |
1 |
實驗樓 |
|
1
|
軟件工程是把系統的、有序的、可量化的方法應用到軟件的開發、運營和維護上的過程。軟件工程包括下列領域:軟件需求分析、軟件設計、軟件構建、軟件測試和軟件維護。 人們在開發、運營、維護軟件的過程當中有不少技術、作法、習慣和思想體系。軟件工程把這些相關的技術和過程統一到一個體系中,叫「軟件開發流程」。軟件開發流程的目的是爲了提升軟件開發、運營、維護的效率,並提升軟件的質量、用戶滿意度、可靠性和軟件的可維護性。 光有各類流程的思想是不夠的,咱們還要有一系列的工具來保證這些思想可以在實踐中有效率地運做。軟件開發很重要的一點不是看你能對多少理論講的頭頭是道,還要看你對相關工具應用的如何,好比Java中單元測試要和JUnit的應用結合起來,建模要和Umbrello或StarUML的應用結合起來。編程學習是一個習而學
的過程。 一個常見的公式是:軟件工程=開發流程+工具
鄒欣老師給出的兩個公式:軟件=程序+軟件工程
和軟件企業=軟件+商業模式
開發流程你們能夠參考學習鄒欣老師的軟件團隊和開發流程。常見的開發流程有:
敏捷開發(Agile Development)是一種以人爲核心、迭代、按部就班的開發方法。「敏捷流程」是一系列價值觀和方法論的集合。從2001年開始,一些軟件界的專家開始倡導「敏捷」的價值觀和流程,他們確定了流行作法的價值,可是強調敏捷的作法更能帶來價值。
敏捷開發包括不少模式:
其中,極限編程(eXtreme Programming,XP)是是一種全新而快捷的軟件開發方法。XP團隊使用現場客戶、特殊計劃方法和持續測試來提供快速的反饋和全面的交流:
XP軟件開發是什麼樣的
經過 XP準則來表達:
一項實踐在XP環境中成功使用的依據經過XP的法則
呈現,包括:快速反饋、假設簡單性、遞增更改、提倡更改、優質工做。
XP軟件開發的基石是XP的活動
,包括:編碼、測試、傾聽、設計。
項目成員用戶成功執行XP活動的技術經過XP實踐
來呈現,包括編程、團隊、過程相關的12條實踐:
咱們關注其中的編碼標準
,結對編程
,代碼集體全部
,測試
,重構
等實踐。上次實驗已經講過TDD,經過學習這些實踐,能夠造成以測試爲核心的開發流程:
敏捷能夠做爲一種作事的方式,掌握好的在之後的工做中也會受益無窮。
編寫代碼一個重要的認識是「程序大多時候是給人看的」,編程標準使代碼更容易閱讀和理解,甚至能夠保證其中的錯誤更少。編程標準包含:具備說明性的名字、清晰的表達式、直截了當的控制流、可讀的代碼和註釋,以及在追求這些內容時一致地使用某些規則和慣用法的重要性。
編碼標準中的版式就是一個很好的例子,版式雖然不會影響程序的功能,但會影響可讀性。程序的版式追求清晰、美觀,是程序風格的重要因素。
咱們常見的是這樣的代碼:
public class CodeStandard { public static void main(String [] args){ StringBuffer buffer = new StringBuffer(); buffer.append('S'); buffer.append("tringBuffer"); System.out.println(buffer.charAt(1)); System.out.println(buffer.capacity()); System.out.println(buffer.indexOf("tring")); System.out.println("buffer = " + buffer.toString()); if(buffer.capacity()<20) buffer.append("1234567"); for(int i=0; i<buffer.length();i++) System.out.println(buffer.charAt(i)); } }
程序沒有最基本的縮進,讓人讀起來很費勁,這個問題在Eclipse中比較容易解決,咱們單擊Eclipse菜單中的source
->Format
或用快捷鍵Ctrl+Shift+F
就能夠按Eclipse規定的規範縮進。
代碼標準中很重要的一項是如何給包、類、變量、方法等標識符命名,能很好的命名可讓本身的代碼立立刻升一個檔次。Java中的通常的命名規則有:
標識符名字應當直觀且能夠拼讀,可望文知意,沒必要進行「解碼」,通常採用英文單詞或其組合,便於記憶和閱讀,切忌使用漢語拼音來命名,用詞要準確例如「當前值」應該起名currentValue
,寫成nowValue
就不許確了,但還湊合,寫成dqz
(dang qian zhi 首字母)就是笑話了。
標識符的長度「min-length && max-information」
的原則,好比:maxVal
比maxValueUntilOverflow
要好些,能夠經過去元音法把變量名變短,如returnValue
->rtnVal
,message
->msg
;通常全局變量用具備說明性的名字,局部變量用短名字:單字符的名字,常見的如i,j,k等用做局部變量。
其餘的能夠參考鄒欣老師寫的代碼規範與代碼複審.
關於代碼標準,能夠遵循如下原則:
有一些公司好比Google公開了本身的編碼標準,能夠做爲學習不錯的參考,你們參考一下範飛龍老師寫的代碼規範&代碼風格,有興趣的能夠嘗試如何在Eclipse中實踐Google Java Style(中文版),也就是說如何作到「按一下快捷鍵Ctrl+Shift+F
就可讓本身的代碼符合Google Java Style(中文版)的要求」,完成後單獨寫一篇Blog,有加分的。
結對編程是XP中的重要實踐。在結對編程模式下,一對程序員肩並肩、平等地、互補地進行開發工做。他們並排坐在一臺電腦前,面對同一個顯示器,使用同一個鍵盤、同一個鼠標一塊兒工做。他們一塊兒分析,一塊兒設計,一塊兒寫測試用例,一塊兒編碼,一塊兒作單元測試,一塊兒作集成測試,一塊兒寫文檔等。 結對編程中有兩個角色:
如何結對編程,爲什麼要結對編程,你們參考一下結對編程和兩人合做 ,重點是:
團隊精神是好多地方都強調的一個精神,最小的團隊就是一對一的二人團隊了,培養團隊精神從結對編程開始吧。社會生活中人與人相處最重要的是誠信,有同理心,互利。結對編程中你們會出現分歧,如何更有效地合做要作到對事不對人
,掌握這些是能夠終生受益的,如何影響小夥伴,你們參考一下兩人合做:要會作漢堡包。
XP的集體全部制意味着每一個人都對全部的代碼負責;這一點,反過來又意味着每一個人均可以更改代碼的任意部分。結對編程
對這一實踐貢獻良多:藉由在不一樣的結對中工做,全部的程序員都能看到徹底的代碼。集體全部制的一個主要優點是提高了開發程序的速度,由於一旦代碼中出現錯誤,任何程序員都能修正它。 這意味着代碼要放到一個你們都能方便獲取的地方,咱們叫代碼倉庫。這引出另一個話題叫版本控制(Version Control)。
不管是對於團隊仍是個體,版本控制都提供了不少好處。
流行的版本控制工具備CVS,SVN,Git等,更多的能夠參考這裏。Git是Linus除了Linux操做系統外的另一個重要發明。
首先開通個人代碼庫功能。
咱們給一個HelloWorld
的例子: 首先進入Code
目錄,你會發現有了shiyanlou_cs212
目錄,進入shiyanlou_cs212
,建立HelloWorld
目錄,建立並編輯HelloWorld.java
文件
以下圖所示:
注意一點,往代碼庫提交的代碼必定編譯、運行、測試都沒有問題的代碼,咱們上面測試代碼沒有問題了,就能夠提交了:
如圖:咱們能夠先用git status
查看一下代碼狀態,顯示有未跟蹤的代碼,並建議用git add <file>...
添加,咱們使用git add HelloWorld.*
把要提交的文件的信息添加到索引庫中。當咱們使用git commit
時,git將依據索引庫中的內容來進行文件的提交。這只是在本地操做,關閉實驗環境,會刪除代碼的,若是想把代碼保存到遠程託管服務器中,須要使用git push
,實驗完成前,必定不要忘了使用git push
,不然就是至關於你在Word中編輯了半天文件最後卻沒有保存。 咱們能夠修改HelloWorld.java
,以下圖所示:編譯、運行、測試沒有問題後進行提交,這兒使用的是git commit -a
:
咱們能夠經過git log
查看代碼提交記錄:
咱們先看看重構的概念:
重構(Refactor),就是在不改變軟件外部行爲的基礎上,改變軟件內部的結構,使其更加易於閱讀、易於維護和易於變動 。
重構中一個很是關鍵的前提就是「不改變軟件外部行爲」,它保證了咱們在重構原有系統的同時,不會爲原系統帶來新的BUG,以確保重構的安全。如何保證不改變軟件外部行爲?重構後的代碼要能經過單元測試。如何使其更加易於閱讀、易於維護和易於變動?設計模式給出了重構的目標。
重構重要嗎?你看看Eclipse菜單中有個refactor
菜單就知道了,重構幾乎是現代IDE的標配了
咱們在編碼標準
中說「給標識符命名」是程序員一項重要技能,之前沒有這個意識,如今知道了怎麼辦?沒問題,上圖中重構的第一項功能就是Rename
,能夠給類、包、方法、變量更名字。
修改方法是,用鼠標單擊要改的名字,選擇Eclipse中菜單中的Refactor
->Rename...
:
學過C語言的學生學Java時常犯的毛病是不會封裝,該用類的地方都用告終構體。好比要定義一個類Student
,會出現這樣的代碼:
Eclipse中菜單中的Refactor
->Encapsulate Field...
注意分析一下重構先後的代碼變化:
一樣能夠封裝id
和age
兩個成員變量,結果以下:
每次打印學生信息都這麼寫代碼違反了DRY原則,形成代碼重複,正常的重構可使用Eclipse中的Extract Method...
因爲Java中全部的類都有個專門的toString方法,咱們使用Eclipse中Source
->Generate toString()...
給Student
類產生一個toString
方法
修改main的代碼,結果以下:
(如下爲閱讀了解的)
咱們要修改軟件,萬變不離其宗,無非就是四種動機:
第一種和第二種動機,都是源於客戶的功能需求,而第四種是源於客戶的非功能需求。軟件的外部質量,其衡量的標準就是客戶對軟件功能需求與非功能需求的滿意度。它涉及到一個企業、一個軟件的信譽度與生命力,所以爲全部軟件企業所高度重視。要提升軟件內部質量,毫無疑問就是軟件修改的第三個動機:改善原有程序的結構。它的價值是隱性的,並不體如今某一次或兩次開發中,而是逐漸體如今往後長期維護的軟件過程當中。 高質量的軟件,能夠保證開發人員(即便是新手)可以輕易看懂軟件代碼,可以保證往後的每一次軟件維護均可以輕易地完成(不論軟件經歷了多少次變動,維護了多少年),可以保證往後的每一次需求變動都可以輕易地進行(而不是傷筋動骨地大動)。要作到這幾點其實並不容易,它須要咱們持續不斷地對系統內部質量進行優化與改進。這,就是系統重構的價值。 下面一個重要問題是哪些地方須要重構?有臭味道(Bad Smell)的代碼。 什麼是臭味道?想象一下你打開冰箱門,出來一股臭味道你就知道冰箱裏有東西腐壞了,要清除了。代碼同樣有臭味道:
臭味行列中首當其衝的就是Duplicated Code(重複的代碼)。若是你在一個以上的地點看到相同的程序結構,那麼當可確定:設法將它們合而爲一,程序會變得更好。
Duplicated Code
就是[同一個class內的兩個方法含有相同表達式(expression)]。這時候你須要作的就是採用Extract Method
提煉出重複的代碼,而後讓這兩個地點都調用被提煉出來的那一段代碼。Extract Method
,而後再對被提煉出的代碼使用Pull Up Method
,將它推入superclass內。Extract Method
將類似部分和差別部分割開,構成單獨一個方法。而後你可能發現或許能夠運用Form Template Method
得到一個Template Method
設計模式。Substitute Algorithm
將其它方法的算法替換掉。Duplicaded Code
,你應該考慮對其中一個使用Extract Class
,將重複代碼提煉到一個獨立class中,而後在另外一個class內使用這個新class。可是,重複代碼所在的方法也可能的確只應該屬於某個class,另外一個class只能調用它,抑或這個方法可能屬於第三個class,而另兩個classes應該引用這第三個class。你必須決定這個方法放在哪兒最合適,並確保它被安置後就不會再在其它任何地方出現。其餘Bad Smell
與相應的重構手法以下表所示:
Eclipse中Refactor
菜單中的重構手法的應用時機以下圖所示:
一個完整的重構流程包括:
1、題目簡介
一個簡單的掃雷小遊戲,在12*12的方格盤上,首先能夠設定雷的個數,而後點擊開始程序就會隨機佈雷,開始遊戲後若是點到雷就會顯示遊戲結束,若是沒有,會出現數字表示周圍一圈雷的個數,以此推理當掃出全部雷將顯示遊戲勝利。
2、實驗結隊分工
3、代碼
package shiyan3;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Frame extends JFrame {
private static final long serialVersionUID = 6929664228252319515L;
JTextField text;
JLabel nowBomb, setBomb;
int BombNum, BlockNum; // 當前雷數,當前方塊數
int rightBomb, restBomb, restBlock; // 找到的地雷數,剩餘雷數,剩餘方塊數
JButton start = new JButton(" 開始 ");
JPanel MenuPamel = new JPanel();
JPanel bombPanel = new JPanel();
Bomb[][] bombButton;
JPanel c;
BorderLayout borderLayout1 = new BorderLayout();
GridLayout gridLayout1 = new GridLayout();
public Frame() {
try {
setDefaultCloseOperation(EXIT_ON_CLOSE);
jbInit();
} catch (Exception exception) {
exception.printStackTrace();
}
}
private void jbInit() throws Exception {
c = (JPanel) getContentPane();
setTitle("掃雷");
c.setBackground(Color.WHITE);
MenuPamel.setBackground(Color.GRAY);
c.setLayout(borderLayout1);
setSize(new Dimension(600, 600));
setResizable(false);
BlockNum = 144;
BombNum = 10;
text = new JTextField("10 ", 3);
nowBomb = new JLabel("當前雷數" + ":" + BombNum);
setBomb = new JLabel("設置地雷數");
start.addActionListener(new Frame1_start_actionAdapter(this));
MenuPamel.add(setBomb);
MenuPamel.add(text);
MenuPamel.add(start);
MenuPamel.add(nowBomb);
c.add(MenuPamel, java.awt.BorderLayout.SOUTH);
bombPanel.setLayout(gridLayout1);
gridLayout1.setColumns((int) Math.sqrt(BlockNum));
gridLayout1.setRows((int) Math.sqrt(BlockNum));
bombButton = new Bomb[(int) Math.sqrt(BlockNum)][(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].setSize(10, 10);
bombButton[i][j].setFont(new Font("", Font.PLAIN, 14));// 設置字體大小
bombButton[i][j].setForeground(Color.white);
bombButton[i][j].addMouseListener(new Bomb_mouseAdapter(this));
bombButton[i][j]
.addActionListener(new Bomb_actionAdapter(this));
bombPanel.add(bombButton[i][j]);
}
}
c.add(bombPanel, java.awt.BorderLayout.CENTER);
startBomb();
}
/* 開始按鈕 */
public void start_actionPerformed(ActionEvent e) {
int num = Integer.parseInt(text.getText().trim());
if (num >= 5 && num < 50) {
BombNum = num;
startBomb();
} else if (num < 5) {
JOptionPane.showMessageDialog(null, "您設置的地雷數太少了,請重設!", "錯誤",
JOptionPane.ERROR_MESSAGE);
num = 10;
BombNum = num;
} else {
JOptionPane.showMessageDialog(null, "您設置的地雷數太多了,請重設!", "錯誤",
JOptionPane.ERROR_MESSAGE);
num = 10;
BombNum = num;
}
}
/* 開始,佈雷 */
public void startBomb() {
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].isRight = false;
bombButton[i][j].BombFlag = 0;
bombButton[i][j].BombRoundCount = 9;
bombButton[i][j].setEnabled(true);
bombButton[i][j].setText("");
bombButton[i][j].setFont(new Font("", Font.PLAIN, 14));// 設置字體大小
bombButton[i][j].setForeground(Color.BLUE);
rightBomb = 0;
restBomb = BombNum;
restBlock = BlockNum - BombNum;
}
}
for (int i = 0; i < BombNum;) {
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) {
bombButton[x][y].isBomb = true;
i++;
}
}
CountRoundBomb();
}
/* 計算方塊周圍雷數 */
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) {
for (int x = i - 1; x < i + 2; x++) {
for (int y = j - 1; y < j + 2; y++) {
if ((x >= 0) && (y >= 0)
&& (x < ((int) Math.sqrt(BlockNum)))
&& (y < ((int) Math.sqrt(BlockNum)))) {
if (bombButton[x][y].isBomb == true) {
count++;
}
}
}
}
bombButton[i][j].BombRoundCount = count;
}
}
}
}
/* 是否挖完了全部的雷 */
public void isWin() {
restBlock = BlockNum - BombNum;
for (int i = 0; i < (int) Math.sqrt(BlockNum); i++) {
for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {
if (bombButton[i][j].isClicked == true) {
restBlock--;
}
}
}
if (rightBomb == BombNum || restBlock == 0) {
JOptionPane.showMessageDialog(this, "您挖完了全部的雷,您勝利了!", "勝利",
JOptionPane.INFORMATION_MESSAGE);
startBomb();
}
}
/** 當選中的位置爲空,則翻開周圍的地圖* */
public void isNull(Bomb ClickedButton) {
int i, j;
i = ClickedButton.num_x;
j = ClickedButton.num_y;
for (int x = i - 1; x < i + 2; x++) {
for (int y = j - 1; y < j + 2; y++) {
if (((x != i) || (y != j)) && (x >= 0) && (y >= 0)
&& (x < ((int) Math.sqrt(BlockNum)))
&& (y < ((int) Math.sqrt(BlockNum)))) {
if (bombButton[x][y].isBomb == false
&& bombButton[x][y].isClicked == false
&& bombButton[x][y].isRight == false) {
turn(bombButton[x][y]);
}
}
}
}
}
/* 翻開 */
public void turn(Bomb ClickedButton) {
ClickedButton.setEnabled(false);
ClickedButton.isClicked = true;
if (ClickedButton.BombRoundCount > 0) {
ClickedButton.setText(ClickedButton.BombRoundCount + "");
} else {
isNull(ClickedButton);
}
}
/* 左鍵點擊 */
public void actionPerformed(ActionEvent e) {
if (((Bomb) e.getSource()).isClicked == false
&& ((Bomb) e.getSource()).isRight == false) {
if (((Bomb) e.getSource()).isBomb == false) {
turn(((Bomb) e.getSource()));
isWin();
}
else {
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].setText("b");
}
}
}
((Bomb) e.getSource()).setForeground(Color.RED);
((Bomb) e.getSource()).setFont(new Font("", Font.BOLD, 20));
((Bomb) e.getSource()).setText("X");
JOptionPane.showMessageDialog(this, "你踩到地雷了,按肯定重來", "踩到地雷", 2);
startBomb();
}
}
}
/* 右鍵點擊 */
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 (restBomb > 0) {
bombSource.setForeground(Color.RED);
bombSource.setText("F");
bombSource.isRight = true;
restBomb--;
} else {
bombSource.BombFlag = 0;
}
} else if (bombSource.BombFlag == 2) {
restBomb++;
bombSource.setText("Q");
bombSource.isRight = false;
} else {
bombSource.setText("");
}
if (bombSource.isBomb == true) {
if (bombSource.BombFlag == 1) {
rightBomb++;
} else if (bombSource.BombFlag == 2) {
rightBomb--;
}
}
nowBomb.setText("當前雷數" + ":" + restBomb);
isWin();
}
}
public static void main(String[] args) {
Frame frame = new Frame();
frame.setVisible(true);
}
}
class Frame1_start_actionAdapter implements ActionListener {
private Frame adaptee;
Frame1_start_actionAdapter(Frame adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.start_actionPerformed(e);
}
}
// //////////////////////////
class Bomb extends JButton {
private static final long serialVersionUID = 2550424246611071294L;
int num_x, num_y; // 第幾號方塊
int BombRoundCount; // 周圍雷數
boolean isBomb; // 是否爲雷
boolean isClicked; // 是否被點擊
int BombFlag; // 探雷標記
boolean isRight; // 是否點擊右鍵
public Bomb(int x, int y) {
num_x = x;
num_y = y;
BombFlag = 0;
BombRoundCount = 9;
isBomb = false;
isClicked = false;
isRight = false;
}
}
class Bomb_actionAdapter implements ActionListener {
private Frame adaptee;
Bomb_actionAdapter(Frame adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.actionPerformed(e);
}
}
class Bomb_mouseAdapter extends MouseAdapter {
private Frame adaptee;
Bomb_mouseAdapter(Frame adaptee) {
this.adaptee = adaptee;
}
public void mouseClicked(MouseEvent e) {
adaptee.mouseClicked(e);
}
}
4、運行結果截圖:
初始界面:
設置雷數爲10,開始遊戲,會顯示數字:
踩到雷,遊戲結束:
掃完雷,遊戲勝利:
5、心得體會
經過結對項目,我認識到了合做的重要性,緊密的合做可以提升咱們的能力。代碼測試過程當中出現不少錯誤,但通過互相的合做和探討,加以改進,即可以成功運行。
統計的PSP(Personal Software Process)時間
步驟 |
耗時(min) |
百分比 |
需求分析 |
20~30 |
10% |
設計 |
40~50 |
20% |
代碼實現 |
90~100 |
40% |
測試 |
40~50 |
20% |
分析總結 |
20~25 |
10% |