合作者: 201631062626 201631062522
代碼位址: https://gitee.com/iy2524/WordCount2.0
本次作業連結位址: https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2188
一、PSP表格
PSP2.1 | PSP階段 | 預估耗時 (分鐘) | 實際耗時 (分鐘) |
Planning | 計劃 | 20 | 10 |
· Estimate | · 估計這個任務需要多少時間 | 20 | 10 |
Development | 開發 | 1200 | 1600 |
· Analysis | · 需求分析 (包括學習新技術) | 30 | 10 |
· Design Spec | · 生成設計文檔 | 10 | |
· Design Review | · 設計複審 (和同僚稽核設計文檔) | 30 | |
· Coding Standard | · 代碼規範 (為目前的開發制定合适的規範) | 60 | 90 |
· Design | · 具體設計 | 300 | 240 |
· Coding | · 具體編碼 | 600 | 900 |
· Code Review | · 代碼複審 | 30 | 100 |
· Test | · 測試(自我測試,修改代碼,送出修改) | 140 | 260 |
Reporting | 報告 | 100 | 50 |
· Test Report | · 測試報告 | 30 | |
· Size Measurement | · 計算工作量 | 35 | 10 |
· Postmortem & Process Improvement Plan | · 事後總結, 并提出過程改進計劃 | 35 | 40 |
合計 | 1320 | 1660 |
二、代碼互審情況
審查子產品: WordCount類 和 用戶端類
發現的問題: 方法名不符合規範,應符合lowerCamelCase來進行命名;注釋該單獨占一行;對檔案進行統計的每個方法都單獨各自對檔案進行了操作,可以将檔案操作分離開來,提升程式的效率;
三、設計過程
類的總體設計為三個類,一個為FileCount類,考主要起到javabean的作用,封裝了如單詞數,字母數,檔案path等屬性。一個為WordCountUtil類,裡面包含操作FileCount的屬性的方法以及一些常量。最後一個Main類即為用戶端類,為程式的啟動入口,通過生成FileCount對象并調用WordCountUtil的靜态方法來實作功能。
類圖:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuATMyADMxMDM00CO4cjNxQTM3EjNxATM4EDMy0yM0MDO4QTMvwFMxgTMwIzLcNDNzgDO0EzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
關鍵函數算法設計:
總體流程:
擷取單詞數:
擷取字元數: 使用String.length()方法即可擷取
擷取行數:隻要在循環中,行數就加一
擷取特殊行數:根據相應條件判斷目前行的類型
擷取結果:
遞歸處理檔案夾所有檔案:
三、代碼說明
本次項目嚴格按照阿裡巴巴java程式設計規範執行,變量和方法命名采用lowerCamelCase,類名采用UpperCamelCase
類前面需要注釋作者資訊,方法需要注釋作者、參數及傳回值資訊,代碼注釋需要單獨一行
以及編碼過程中的魔法值需要設定成常量友善維護
在擷取結果方法中,傳入參數清單、檔案統計對象,并通過單行讀取執行相應的方法,将結果儲存到檔案統計對象裡
/**
* 讀取檔案,并将結果儲存到fileCount對象裡
* @param orderList 參數清單
* @param fileCount 檔案對象
* @throws Exception
*/
public static void getResults(List<Integer> orderList, FileCount fileCount) throws Exception {
InputStreamReader isr = new InputStreamReader(new FileInputStream(fileCount.getPath()));
BufferedReader br = new BufferedReader(isr);
String tempLine = null;
while ((tempLine = br.readLine()) != null) {
if (orderList.contains(HAS_CHAR)) {
if (fileCount.getCharsNum() == -1) {
fileCount.setCharsNum(0);
}
// 每次換行時會有兩個字元/r/n,計算長度需要加上這兩個字元
fileCount.setCharsNum(fileCount.getCharsNum() + 2 + getCharsNum(tempLine));
}
if (orderList.contains(HAS_WORD)) {
if (fileCount.getWordsNum() == -1) {
fileCount.setWordsNum(0);
}
fileCount.setWordsNum(fileCount.getWordsNum() + getWordsNum(tempLine, stopList));
}
if (orderList.contains(HAS_LINE)) {
if (fileCount.getLinesNum() == -1) {
fileCount.setLinesNum(0);
}
fileCount.setLinesNum(fileCount.getLinesNum() + 1);
}
if (orderList.contains(HAS_LINE_BY_TYPE)) {
if (fileCount.getBlankLinesNum() == -1) {
fileCount.setBlankLinesNum(0);
}
if (fileCount.getCodeLinesNum() == -1) {
fileCount.setCodeLinesNum(0);
}
if (fileCount.getNoteLinesNum() == -1) {
fileCount.setNoteLinesNum(0);
}
switch (tellLineType(tempLine)) {
case NOTE_LINE:
fileCount.setNoteLinesNum(fileCount.getNoteLinesNum() + 1);
break;
case CODE_LINE:
fileCount.setCodeLinesNum(fileCount.getCodeLinesNum() + 1);
break;
case BLANK_LINE:
fileCount.setBlankLinesNum(fileCount.getBlankLinesNum() + 1);
break;
}
}
}
if (fileCount.getCharsNum() != -1) {
// 最後一行沒有換行,減2
fileCount.setCharsNum(fileCount.getCharsNum() - 2);
}
isr.close();
}
統計單詞數的方法為一個通用方法,傳入目前行和停用詞清單,當不需要停用詞時則傳入空清單即可。
/**
* 擷取單詞數
*
* @author MS
*
* @param str 每行的字元串
* @return count 數量
*/
public static int getWordsNum(String str, List<String> stopList) {
int count = 0;
Matcher matcher = null;
boolean isChar = false;
String tempStr = "";
for (int i = 0; i < str.length(); i++) {
matcher = PATTERN.matcher(str.charAt(i) + "");
if (matcher.matches()) {
tempStr += str.charAt(i);
if (i == str.length() - 1 && !stopList.contains(tempStr)) {
count++;
} else {
isChar = true;
}
} else if (isChar == true) {
isChar = false;
if (!stopList.contains(tempStr)) {
count++;
}
tempStr = "";
}
}
return count;
}
/**
* 從檔案中取出以空格隔開的單詞
*
* @param stopFile
* 存放單詞檔案名字字元串 絕對路徑
* @return 取出的單詞字元串集合
* @throws FileNotFoundException
*/
public static List<String> getStopStringList(String stopFile) throws Exception {
List<String> stopList = new ArrayList<>();
BufferedInputStream stop = new BufferedInputStream(new FileInputStream(stopFile));
int x = -1;
String stopStr = "";
char ch;
// 取出停用詞裝到stopList
while (true) {
x = stop.read();
if (x == -1) {
stopList.add(stopStr);
stopStr = "";
stop.close();
break;
}
ch = (char) x;
if (ch == ' ') {
stopList.add(stopStr);
stopStr = "";
} else {
stopStr += ch;
}
}
return stopList;
}
在FileCount類中封裝了檔案統計的屬性,如字元數、單詞數等。
/**
*
*/
package com.test.javabean;
/**
* @author Dylan
*
*/
public class FileCount {
private int charsNum = -1;
private int wordsNum = -1;
private int linesNum = -1;
private int codeLinesNum = -1;
private int noteLinesNum = -1;
private int blankLinesNum = -1;
private String path;
public FileCount(String path) {
this.path = path;
}
public String getPath() {
return path;
}
public int getCharsNum() {
return charsNum;
}
public void setCharsNum(int charsNum) {
this.charsNum = charsNum;
}
public int getWordsNum() {
return wordsNum;
}
public void setWordsNum(int wordsNum) {
this.wordsNum = wordsNum;
}
public int getLinesNum() {
return linesNum;
}
public void setLinesNum(int linesNum) {
this.linesNum = linesNum;
}
public int getCodeLinesNum() {
return codeLinesNum;
}
public void setCodeLinesNum(int codeLinesNum) {
this.codeLinesNum = codeLinesNum;
}
public int getNoteLinesNum() {
return noteLinesNum;
}
public void setNoteLinesNum(int noteLinesNum) {
this.noteLinesNum = noteLinesNum;
}
public int getBlankLinesNum() {
return blankLinesNum;
}
public void setBlankLinesNum(int blankLinesNum) {
this.blankLinesNum = blankLinesNum;
}
}
遞歸檔案
/**
* 遞歸處理目錄裡所有符合條件的檔案
*
* @param path
* 目錄的位置
* @param orderList
* 指令集合
* @param condition
* 限制的條件
* @throws Exception
*/
public static void recursionAllFiles(File catalog, List<Integer> orderList, String condition,
List<FileCount> fileCounts) {
if (catalog != null) {
if (catalog.isDirectory()) {
File[] fileArray = catalog.listFiles();
if (fileArray != null) {
for (int i = 0; i < fileArray.length; i++) {
recursionAllFiles(fileArray[i], orderList, condition, fileCounts);
}
}
} else if (getFileName(catalog.getName(), DOT).equals(condition)) {
FileCount fileCount = new FileCount(catalog.getAbsolutePath());
try {
getResults(orderList, fileCount);
} catch (Exception e) {
// TODO 自動生成的 catch 塊
e.printStackTrace();
}
fileCounts.add(fileCount);
}
}
}
五、總結
在這此項目中,我收獲了很多。在此之間我寫代碼不是很有規範,看着雜亂無章,其實我早就想解決這個問題,通過這次項目,了解到了程式設計規範,花了很多時間去學習規範和使用規範,其中最難改的就是java中大括号的使用,以前是兩個括号上下對齊,阿裡規範要求不一樣,雖然花了很長時間,但體會到了“規矩”帶來的友善和愉悅。還有就是認識到了自己在面向對象設計上的不足,在這次項目中簡單的根據自己了解的部分面向對象思想簡單的設計了類和方法,但在完成所有代碼後發現有很多不足,一個類的作用不是很明顯,這還需要我更深入的學習面向對象和設計模式,相較于計算機其他方面,我從這次項目中發現,我更喜歡軟體系統的設計,今後我會偏向了解學習軟體設計方面的知識,而且一個好的結構設計是一個好的軟體的開始,沒有一個好的架構,軟體的開發和使用都會出現問題。在這個項目我認為結對的效果總體是1+1>2的,雖然在合并項目時,兩人因為結構設計的不一樣,争論了大半天,但最終兩個人達成了一緻的意見,每個人分别完成自己的事情,有問題能互相幫助解決,節省了很多開發時間。
轉載于:https://www.cnblogs.com/stedylan/p/9800361.html