1. 程式人生 > >WordCount 項目總結

WordCount 項目總結

測試 命令 The ret des new true 行數 字符數


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);
    }
  }

解析用戶的參數,需要解決這幾個問題:

  1. 無意義的輸入
  2. 參數的順序(比如 -o 後面跟輸出文件)
  3. 對用戶進行提示

完成後需要封裝為 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

/**/ 多行註釋並不會被統計為註釋。

執行用例

  1. wc.exe -c -w -l -a text.txt -e stopList.txt -o output.txt
  2. wc.exe -xx
  3. wc.exe -c text.txt
  4. wc.exe -e stopList.txt
  5. wc.exe text.txt -o oup.txt
  6. wc.exe fffffffffffffffffffffffffffffffffffffffffffff&&*$##%&

在 5 這個測試中,代碼執行會通過,沒有指定參數,但是含有輸入輸出文件,程序就默認不做操作。(但是還是會進入上面提到的 Operator.class 操作類的方法中)

其他

gitee 管理項目,需要 git 相關知識。基本的配置見這篇文章

從Git合作管理gitee項目淺談

因為管理不當,我在 push 代碼的時候遇到了本地分支和遠程分支沖突的問題,一直沒弄好,最後強制上傳,git push origin master -f 把我之前的 commits 覆蓋完了...

WordCount 項目總結