這個作業屬于哪個課程 | 2019學年02學期單紅老師軟體工程實踐 |
---|---|
這個作業要求在哪裡 | 寒假作業(2/2)連結 |
這個作業的目标 | 開發一個簡易的疫情統計程式 |
作業正文 | 本博文 |
其他參考文獻 | CSDN相關部落格、建構之法 |
GitHub倉庫位址
Benjamin_Gnep疫情統計
PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 30 | |
Estimate | 估計這個任務需要多少時間 | 1890 | 2250 |
Development | 開發 | 960 | 1170 |
Analysis | 需求分析 (包括學習新技術) | 390 | 410 |
Design Spec | 生成設計文檔 | 90 | 120 |
Design Review | 設計複審 | 10 | |
Coding Standard | 代碼規範 (為目前的開發制定合适的規範) | 150 | |
Design | 具體設計 | ||
Coding | 具體編碼 | 480 | 540 |
Code Review | 代碼複審 | 60 | |
Test | 測試(自我測試,修改代碼,送出修改) | 330 | 460 |
Reporting | 報告 | ||
Test Repor | 測試報告 | 20 | |
Size Measurement | 計算工作量 | ||
Postmortem & Process Improvement Plan | 事後總結, 并提出過程改進計劃 | ||
合計 |
需求分析
- 分析外部傳遞的參數并進行不同的資料處理
- 檔案的讀取和寫入
- 具有可拓展性和較強的可讀性、封裝性等
- 檔案的編碼确認
- 字元串的格式處理以及正規表達式的使用
- 檔案的合法性确認
設計思路
- 指令分析使用正規表達式判斷參數和值并且使用map儲存
- 先讀入檔案清單,然後通過date參數進行日志篩選
- 将每個檔案的每行連接配接在一起,然後組成一個待處理文本集進行處理
- 使用責任鍊模式對每行文本進行處理
- province和type可以傳回連結清單,若不存在與表中的元素不予輸出
- 建構一個TxtTool儲存檔案讀入等一系列操作
- 建構一個CmdArgs對讀入的參數與值進行處理
- 省份、類型以及參數使用枚舉類存儲,友善拓展
- 針對上述知識點到相關部落格進行學習和查找
設計實作過程
代碼說明
核心方法-excute
execute代碼存在兩個變量,分别是分析province傳回的省份字元串以及分析type傳回的typeList,主要執行十分簡單,因為ListKey存在編号,是以for循環執行的時候會以log->date->province->type->out的順序執行,友善确認list參數個數以及拓展添加。
@Override
public void execute(Map<String,List<String>>map) {
String proString = null;
List<String> typeString = new LinkedList<String>();
for(int i = 0; i < ListKey.values().length ;i++) {
listKey = ListKey.valueOf(i);
switch(listKey) {
case DATE:
dateKey(map);
result = DataManager.solveData(logLine);
DataManager.mergeData(result);
break;
case LOG:
logKey(map);
break;
case OUT:
outKey(map,proString,typeString);
break;
case TYPE:
typeString = typeKey(map);
break;
case PROVINCE:
proString = provinceKey(map);
break;
}
}
}
枚舉類舉例-ProvinceValue
枚舉類可以很友善的進行資料的存儲編号,在province枚舉類中還可以通過編号的方式事先确定好排序,枚舉類不僅可以在switch中使用,還可以非常友善地進行複用。通過map進行索引還可以由鍵找值,由值尋鍵。
enum ProvinceValue{
China(0,"全國"), Anhui(1,"安徽"),Aomen(2,"澳門"), Beijing(3,"北京")
,Chongqin(4,"重慶"), Fujian(5,"福建"),Gansu(6,"甘肅"), Guangdong(7,"廣東")
,Guangxi(8,"廣西"), Guizhou(9,"貴州"), Hainan(10,"海南"), Hebei(11,"河北")
,Henan(12,"河南"), Heilongjiang(13,"黑龍江"),Hubei(14,"湖北"), Hunan(15,"湖南")
,Jiangsu(16,"江蘇"), Jiangxi(17,"江西"), Jilin(18,"吉林"), Liaoning(19,"遼甯")
,Neimenggu(20,"内蒙古"), Ningxia(21,"甯夏"),Qinghai(22,"青海")
,Shandong(23,"山東"),Shanxi(24,"山西"),ShanXi(25,"陝西"),Shanghai(26,"上海")
,Sichuan(27,"四川"),Taiwan(28,"台灣"),Tianjin(29,"天津"),Xizang(30,"西藏")
,Xinjiang(31,"新疆"),Xianggang(32,"香港"), Yunnan(33,"雲南"),Zhejiang(34,"浙江");
private int key;
private String text;
private ProvinceValue(int key,String text){
this.key = key;
this.text = text;
}
private static HashMap<Integer,String> map = new HashMap<Integer,String>();
static {
for(ProvinceValue d : ProvinceValue.values()){
map.put(d.key,d.text);
}
}
public static int keyOfProvince(String string) {
for (Entry<Integer, String> entry : map.entrySet()) {
if (string.contains(entry.getValue())) {
return entry.getKey();
}
}
return -1;
}
public static ProvinceValue valueOf(int ordinal) {
if (ordinal < 0 || ordinal >= values().length) {
throw new IndexOutOfBoundsException("Invalid ordinal");
}
return values()[ordinal];
}
String getText() {
return text;
}
int getKey() {
return key;
}
}
資料存儲-Map(String,List)
在類與類之間需要由資料結構進行資料傳遞,使用hashmap可以保證安全性的同時,将多種資料結構集合在一起,并且可以一一對應,不會造成一值多鍵的情況。分析指令行時,以‘-’作為識别參數的方式,再将參數後到另一參數前的值全部存取到list中,這樣可以解決多值參數的問題,同時也確定每一個單詞都被擷取。
public Map<String, List<String>> fillMap(Map<String, List<String>> map) {
String key;
List<String> value;
while(index < args.length) {
key = argKey();
key = key.toLowerCase().trim();
value = argVals();
map.put(key, value);
}
return map;
}
String argKey() {
if(index<args.length && args[index].matches(Constant.COMMAND_REG)) {
//index 作為現在處理到的位置
String[] key = args[index].split(Constant.SPILT_COMMAND);
index++;
//System.out.println(key[1]);
return key[1];
}
return null;
}
List<String> argVals() {
List<String> values = new LinkedList<String>();
while(index<args.length && (!args[index].matches(Constant.COMMAND_REG))) {
//将參數所有的值放入values中
values.add(args[index]);
index++;
}
Iterator<String> it = values.iterator();
if(!it.hasNext()) {
values.add(Constant.DEFAULT);
}
return values;
}
責任鍊模式-MyHandler
責任鍊模式可以很友善地拓展需求,一個類的修改不會影響另外一個類,利用Handler虛拟類,衍生出所有處理各類情況的類,確定可以處理每一種情況的文本,同時也減少了程式的耦合性,友善閱讀。
class DataManager{
public static List<int[]> solveData(List<String>data){
List<int[]> result = new LinkedList<int[]>();
ListInit(result);
System.out.println("建立責任鍊");
AddipHandler addip = new AddipHandler(result);
AddSpHandler addSp = new AddSpHandler(result);
ChangeHandler change = new ChangeHandler(result);
CureHandler cure = new CureHandler(result);
DeathHandler death = new DeathHandler(result);
ExcludeHandler exclude = new ExcludeHandler(result);
SwapIpHandler swapIp = new SwapIpHandler(result);
SwapSpHandler swapSp = new SwapSpHandler(result);
addip.nextHandler = addSp;
addSp.nextHandler = change;
change.nextHandler = cure;
cure.nextHandler = death;
death.nextHandler = exclude;
exclude.nextHandler = swapIp;
swapIp.nextHandler = swapSp;
swapSp.nextHandler = null;
System.out.println("建立責任鍊完成,開始處理文本");
Iterator<String> it = data.iterator();
while(it.hasNext()) {
String s = it.next();
addip.handleRequest(s);
}
System.out.println("---文本處理完成");
return result;
}
//......
}
單元測試
測試字元串為下列字元串數組,輸入輸出目錄為了友善放在了學号下
dateScreen方法作為檔案清單的篩選,可以看出,篩選掉了01-23後的日期檔案
dateKey方法作為篩選檔案、整合檔案的方法,可以看出把所有待處理檔案(去掉注釋後)完整的連接配接在一起
輸出到檔案的内容經過驗證無誤
覆寫率以及性能
作為主要方法的ListCommand,除了各個方法内必要的空值判定外,其他代碼均已覆寫,核心方法execute覆寫率為百分百
責任鍊的代碼覆寫率也達到了百分之百
部分工具類的使用情況:覆寫率也基本達到了90%以上
以下為性能測試圖
代碼規範
Benjamin_Gnep代碼規範
心路曆程
初看到這個需求,滿腦子沒有一點思路。
的确要感謝很多同學的幫助,讓我明白了如何了解一些複雜難懂的概念,然後慢慢開始梳理怎麼開始進行編碼。
B站真不愧是學習網站,我在上面找到了相關的入門教程,對于Git和Github都有了初步的了解,視訊教程相對于博文來講更加容易了解。
之後通過相關博文,我就開始對設計模式的指令模式和責任鍊模式進行學習,腦袋裡有了初步的想法,包括枚舉類和一些工作類的編寫,然後整理了我的文本處理思路,便開始了初步的編寫,基本上都是邊寫邊查,遇到知識盲區就看看别人的代碼,查查别人的隻是總結,還是有很多收獲的。
我在建構方法的時候盡量把功能細化,是以可能會導緻代碼量特别多,但是對于一些簡單的方法複用率就高一些。
"軟體=程式+軟體工程"
建構之法的閱讀我明白了很多代碼規範,團隊協作的關鍵在于如何讓别人讀懂你的程式,你可能可以把這個功能實作的很完美,但是沒有規範沒有注釋的代碼就是一坨狗屎。别人不可能花大量的時間收拾你的爛攤子。
Github前端相關倉庫
Front-end-Developer-Interview-Questions 面試題集合
bootstrap 架構
Front-end-Collect 優秀網站、部落格、活躍開發者
Vue 架構
Javascript 須知
希望以後的生活一日三餐,一年四季。