標籤:
實驗內容1. XP基礎2. XP核心實踐3. 相關工具
實驗步驟(一)敏捷開發與XP
軟體工程包括下列領域:軟體需求分析、軟體設計、軟體構建、軟體測試和軟體維護。
標識符名字應當直觀且可以拼讀,可望文知意,不必進行“解碼”,一般採用英文單詞或其組合,便於記憶和閱讀,切忌使用漢語拼音來命名,用詞要準確例如“當前值”應該起名currentValue
,寫成nowValue
就不準確了,但還湊合,寫成dqz
(dang qian zhi 首字母)就是笑話了。
標識符的長度“min-length && max-information”
的原則,比如:maxVal
比 maxValueUntilOverflow
要好些,可以通過去母音法把變數名變短,如returnValue
->rtnVal
,message
->msg
;一般全域變數用具有說明性的名字,局部變數用短名字:單字元的名字,常見的如i,j,k等用作局部變數。
(二)編碼通訊協定
編寫代碼一個重要的認識是“程式大多時候是給人看的”,編程標準使代碼更容易閱讀和理解,甚至可以保證其中的錯誤更少。編程標準包含:具有說明性的名字、清晰的運算式、直截了當的控制流程、可讀的代碼和注釋,以及在追求這些內容時一致地使用某些規則和慣用法的重要性。
標識符的長度“min-length && max-information”
的原則,比如:maxVal
比 maxValueUntilOverflow
要好些,可以通過去母音法把變數名變短,如returnValue
->rtnVal
,message
->msg
;一般全域變數用具有說明性的名字,局部變數用短名字:單字元的名字,常見的如i,j,k等用作局部變數。
Java中的一般的命名規則有:
- 要體現各自的含義
- 包、類、變數用名詞
- 方法名用動賓
- 包名全部小寫,如:io,awt
- 類名第一個字母要大寫,如:HelloWorldApp
- 變數名第一個字母要小寫,如:userName
- 方法名第一個字母要小寫:setName
(三)結對程式設計
武西垚工作:加註釋,測試代碼,加圖片
鄭偉:寫主函數,完善各模組
結對同學:20135332
http://www.cnblogs.com/wuxiyao/
拼圖遊戲
* JAVA小遊戲-拼圖 我做的第一個小遊戲 * Cell類是繼承的按鈕類,並加上相應圖形,形成方格 *MyCanvas是一個面板,載入Cell類的對象(方格),是這三個類中的核心 *
*/
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); } }
}
(四)版本控制
注意一點,往程式碼程式庫提交的代碼一定編譯、運行、測試都沒有問題的代碼,我們上面測試代碼沒有問題了,就可以提交了: 我們可以先用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
,可以給類、包、方法、變數改名字。 例如這有個ABC
類:
這個類,類名,方法名和方法的參數名都有問題,沒有注釋的話是無法理解代碼的。我們可以使用Eclipse中的重構功能來改名。修改方法是,用按一下滑鼠要改的名字,選擇Eclipse中菜單中的Refactor
->Rename...
:
重構完的效果如下:
功能不變,代碼水平立馬上了一個檔次,體會到命名的威力了吧?
Eclipse中菜單中的Refactor
->Encapsulate Field...
,如:
注意分析一下重構前後的代碼變化: 同樣可以封裝id
和age
兩個成員變數,結果如下:
上面第34,35行還是有問題的,每次列印學生資訊都這麼寫代碼違反了DRY原則,造成代碼重複,正常的重構可以使用Eclipse中的Extract Method...
,如:
由於Java中所有的類都有個專門的toString方法,我們使用Eclipse中Source
->Generate toString()...
給Student
類產生一個toString
方法,如:
修改main的代碼,結果如下:
大家想一想,這樣重構後有什麼好處?重構有什麼問題嗎?
我們要修改軟體,萬變不離其宗,無非就是四種動機:
- 增加新功能;
- 原有功能有BUG;
- 改善原有程式的結構;
- 最佳化原有系統的效能 。
- 最單純的
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
與相應的重構手法如下表所示:
Eclipse中Refactor
菜單中的重構手法的應用時機如所示:
更完整的手法可以參考《重構》作者Martin Fowler的部落格。Eclipse中基本手法的使用大家可以參考任何人都可以重構來進行學習實踐。
一個完整的重構流程包括:
- 從版本控制系統程式碼程式庫中Check out code
- 讀懂代碼(包括測試代碼)
- 發現bad smell
- Refactoring
- 運行所有的Unit Tests
- 往程式碼程式庫中Check in code
我們結合Git給出一個比較完整的例子。
(六)實踐項目1. 以結對程式設計的方式編寫一個軟體,Blog中要給出結對同學的Blog網址,可以拍照展現結對程式設計情況,可以參考一下其他學校的作業
結對同學:20135322
http://www.cnblogs.com/zhengwei0712/
2.記錄TDD和重構的過程,測試代碼不要少於業務代碼,Eclipse中
refactor
菜單下的重構技能不要少於5個
3.團隊代碼要使用git在實驗樓中託管,要使用結對同學中的一個同學的帳號託管。4. 程式要有GUI介面,參考使用者介面和使用者體驗5.程式功能從豌豆莢遊戲中選擇一款用Java實現,注意:
團隊之間項目不能有重複,課代表協調一下。
JAVA第三次實驗