WordCount 項目總結
layout: post
title: WordCount 項目總結
date: 2018-09-23
categories: blog
tags: [作業]
description:
---
項目地址
https://gitee.com/hqweay007/WordCount
已完成需求與分析
需求分析
基本功能:統計文件的字符數,單詞數,行數。
擴展功能:統計代碼文件的註釋行數,空行數,代碼行數,使用忽略詞組統計單詞數
將統計結果按照一定格式寫入輸出文件。
打包為可執行文件 wc.exe
。
執行方式:wc.exe 參數
註意
- 空格,水平制表符,換行符,均算字符。
- 由空格或逗號分割開的都視為單詞,且不做單詞的有效性校驗,例如:thi#,that視為用- - 逗號隔開的2個單詞。
- -c, -w, -l參數可以共用同一個輸入文件,形如:wc.exe –w –c file.c 。
- -o 必須與文件名同時使用,且輸出文件必須緊跟在-o參數後面,不允許單獨使用-o參數。
截圖效果
參數違規
正常
采用 stop list文件
PSP表格
PSP2.1 | PSP階段 | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
· Planning | · 計劃 | 30 | 20 |
· Estimate | · 估計這個任務需要多少時間 | 20 | 10 |
· Development | · 開發 | 24*60 | 10*60 |
· Analysis | · 需求分析 (包括學習新技術) | 50 | 40 |
· Design Spec | · 生成設計文檔 | 10 | 10 |
· Design Review | · 設計復審 (和同事審核設計文檔) | 10 | 0 |
· Coding | · 代碼規範 (為目前的開發制定合適的規範) | 10 | 10 |
· Code Review | · 具體設計 | 20 | 30 |
· Test | · 具體編碼 | 24*60 | 15*60 |
· Reporting | · 代碼復審 | 2*60 | 50 |
· Test Report | · 報告 | 2*60 | 1.5*60 |
· Size Measurement | · 測試報告 | 30 | 10 |
· Postmortem & Process | · 計算工作量 | 10 | 15 |
· Improvement Plan | · 事後總結, 並提出過程改進計劃 | 10 | 20 |
· 合計 | 3310 | 1825 |
解題思路
統計字符與行數,第一感覺需要用到文件的輸入輸出知識,然後按行讀取,按字符來進行一些判斷,看是否滿足需求。
類圖
程序設計與代碼說明
在正式寫代碼之前,我先簡單地組織了一下項目。
一
如類圖所示,首先我考慮到需求分析時的基本功能,擴展功能,高級功能這三塊,我註意到每一個模塊要求的功能並不多,所以打算按模塊建立功能類,這樣擴展就只需要新建類,當我完成基本功能去實現高級功能時,就不需要修改完成的代碼。
比如我在 BasicFeature.class
中的代碼
/**
* 基本功能
* 統計 字符,單詞,行數
*/
public class BasicFeature {
Util util = new Util();
/**
* @param file
* @return string of countChar
* @throws IOException
*/
public String countChar(File file) throws IOException {
}
/**
* @param file
* @return string of countWord
* @throws IOException
*/
public String countWord(File file) throws IOException {
}
/**
* @param file
* @return string of coutLine
* @throws IOException
*/
public String countLine(File file) throws IOException {
}
}
對應於需求分析中基本功能的三個功能。
二
其次,需求分析中涉及到對某個名詞的定義,比如以什麽來分隔單詞,什麽是空行。於是我把這類定義放在一個配置類 Config.class
中,可以方便地進行修改。
比如需求中提到:
由空格或逗號分割開的都視為單詞,且不做單詞的有效性校驗
於是我在 Config.class
寫了
//統計單詞的分隔符
//按需求,只需要區分 逗號,空格
//這樣定義便於擴展
public final static String[] supportSplits = {
",", " ", "."
};
三
在編碼過程中,我註意到在每個小功能中,都會涉及到文件的讀取操作,於是我建立了一個配置類 Util.class
,抽象了一個用的最多的文件操作方法。(在之後,我還在此類中放了一些其他方法。)
/**
* 把獲取輸入流獨立出來
*
* @param file
* @return bufferedReader
*/
public BufferedReader getBufferedReader(File file) {
InputStreamReader inputStreamReader = null;
try {
inputStreamReader = new InputStreamReader(new FileInputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
//可能出錯勒
}
return new BufferedReader(inputStreamReader);
}
這樣,就把一個經常用到的流程抽象為了一個方法,可以方便地調用。
四
當我完成了各個模塊,就準備將整個流程整合起來。
按需求分析所說,最終我們需要達到的是通過命令行窗口執行 wc.exe 參數列表
。
這個流程是一定的,所以我建立了一個操作類 Operator.class
,通過調用功能類的方法,達到了封裝整個操作的效果。
根據用戶的參數,我們需要判斷出要執行哪些功能,所以我在此類中添加了如下 5 個屬性。在解析用戶輸入的參數時,就解析出哪些操作是需要執行的。
然後在 excuteCountOperatorToOutput()
方法中,就開始通過調用功能類的方法執行相應功能。
class Operator {
private boolean countChar = false;
private boolean countWord = false;
private boolean countWordByStopList = false;
private boolean countLine = false;
private boolean countCodeInfo = false;
/**
* 執行一系列的統計操作
*
* @param file
* @param stopListFile
* @return
*/
public ArrayList<String> excuteCountOperatorToOutput(File file, File stopListFile) {
ArrayList<String> outputTexts = new ArrayList<String>();
//功能類
BasicFeature basicFeature = new BasicFeature();
EXFeature exFeature = new EXFeature();
try {
if (countChar) {
outputTexts.add(basicFeature.countChar(file));
}
if (countWord) {
outputTexts.add(basicFeature.countWord(file));
}
if (countWordByStopList) {
outputTexts.add(exFeature.countWordByStopList(file, stopListFile));
}
if (countLine) {
outputTexts.add(basicFeature.countLine(file));
}
if (countCodeInfo) {
outputTexts.add(exFeature.countCodeInfo(file));
}
} catch (IOException e) {
e.printStackTrace();
}
return outputTexts;
}
}
整個流程有了,就可以進行階段性的測試。我建立了一個測試類 Test.class
,不過在實際開發過程,我都是直接在主函數中測試的...這一點做的不是很好。
最後,需要和用戶交互,我建立了 Welcome.class
類,這個類主要用於解析用戶輸入的參數。
因為涉及到與用戶的交互,我創建了一個內部類 paramException.class
,用於相關的錯誤提示。
class paramException {
private ArrayList<String> errors = new ArrayList<String>();
public ArrayList<String> getErrors() {
return errors;
}
public void addError(String error) {
this.errors.add(error);
}
}
解析用戶的參數,需要解決這幾個問題:
- 無意義的輸入
- 參數的順序(比如 -o 後面跟輸出文件)
- 對用戶進行提示
完成後需要封裝為 exe 可執行文件,使用的工具是 exe4j ,用到了張波同學在 有關exe4j打包jar包控制臺沒有輸出的補充 的內容。
五
然後涉及到了參數的解析,在命令行執行 wc.exe -a -p
,‘-a‘,‘-p‘ 都會作為 args[] 參數傳進來。
下面是大體流程,其中包含一些小方法,不贅敘。
public boolean paramsExecute(String[] args) {
for (int i = 0; i < args.length; i++) {
String param = args[i];
switch (param) {
case "-c":
countChar();
break;
case "-w":
countWord(args);
break;
case "-l":
countLine();
break;
case "-a":
countCodeInfo();
break;
case "-o":
if (i < args.length - 1 && args[i + 1].contains(".")) {
//輸出文件 ok
} else {
String error = "沒找到輸出文件 " + args[i];
paramException.addError(error);
return false;
}
break;
case "-e":
if (i < args.length - 1 && args[i + 1].contains(".")) {
// count word by stop list
operator.setCountWordByStopList(true);
operator.setCountWord(false);
} else {
String error = "參數 " + args[i] + " 後沒找到 stop list 文件 ";
paramException.addError(error);
return false;
}
break;
default:
//文件名或者報錯
filePaths.add(param);
break;
}
}
return true;
}
測試過程
思路
整個開發流程無時無刻不在測試,系統的測試在基本功能完成後。
因為我的開發流程是:各個小功能,整體,打包 exe 。
所以測試流程也隨之是先通過各個小功能,再整體流程測試,再打包為 exe 可執行文件,在命令行窗口執行。
最後一步的測試效果如 截圖效果 所示。
如類圖所示,我分了 BasicFeature.class,EXFeature.class 兩個功能類,在這兩個功能類裏我通過創建 Main 方法實現了測試方法的效果,達到模塊測試。
我還建立了一個 Test.class 作為後面的整體測試,不過沒怎麽用上,因為代碼比較簡單,直接在 main 函數執行比較方便。
比如:
Welcome welcome = new Welcome();
String[] argsd = {
"-c",
"-w",
"-l",
"-a",
"text.txt",
"-e",
"stopList.txt",
"-o",
"output.txt"
};
//解析參數
welcome.start(argsd);
側重點
因為需求分析中沒做非常嚴格的規定,所以每個小功能還是比較好實現的。比如單詞的分隔僅僅要求以空格,逗號來分隔,不做檢驗。一般只需要按行讀取再做匹配。
我在輸入文件中寫了一些字符做測試。
還有就是與用戶的交互,用戶執行操作的時候什麽參數都可能傳進來,所以要多考慮。
文件用例
text.txt
//public void
/**
*
**/
ddddd
ssss File is a
dd ss
ssss
/**/ 多行註釋並不會被統計為註釋。
執行用例
wc.exe -c -w -l -a text.txt -e stopList.txt -o output.txt
wc.exe -xx
wc.exe -c text.txt
wc.exe -e stopList.txt
wc.exe text.txt -o oup.txt
wc.exe fffffffffffffffffffffffffffffffffffffffffffff&&*$##%&
在 5 這個測試中,代碼執行會通過,沒有指定參數,但是含有輸入輸出文件,程序就默認不做操作。(但是還是會進入上面提到的 Operator.class 操作類的方法中)
其他
用 gitee 管理項目,需要 git 相關知識。基本的配置見這篇文章
從Git合作管理gitee項目淺談
因為管理不當,我在 push 代碼的時候遇到了本地分支和遠程分支沖突的問題,一直沒弄好,最後強制上傳,git push origin master -f
把我之前的 commits 覆蓋完了...
WordCount 項目總結