2016-06-17 39 views
1

我有一個程序,通過逐行讀取每個單元格中的每個單元格,將excel轉換爲數據。相當棘手的代碼嗅到解決(由於兩個單獨的庫)C++

要做到這一點,我已經使用了兩個獨立的庫:

ExcelFormat (for xls)

Xlsx I/O

我有一個抽象類的算法,以及兩個派生類爲每個。我遇到的問題是,ExcelFormat和Xlsx I/O不遵循相同的格式(因爲它們是單獨的庫,並且不符合相同的基類)。

(注意,我寫了xlsxio的包裝,因爲它是程序性的,並且我想OO功能)

我想抽象算法儘可能給基類。現在我所能做的就是擁有通用的抽象方法Convert(),這非常糟糕,因爲這兩個函數算法非常相似,但無法符合統一界面只是因爲他們不共享相同的基礎。

這是我有:

bool XlsxToData::Convert(const std::string & filePath, std::list<SqlParam*>* params) { 
    FreeXlsx::XlsxBook book(filePath); 

    if (book.IsOpen()) { 

     std::vector<std::string>* sheets = book.GetSheetList(); 
     if (sheets != nullptr) { 
      std::list<SqlParam*> foundParams; 

      for (auto itr : *sheets) { 

       FreeXlsx::XlsxSheet sheet(itr, book); 

       std::map<int, SqlParam*> foundX; 

       int longestWidth = 0; 
       int lastWidth = 0; 

       if (sheet.IsOpen()) { 

        sheet.ForSheet([this, &foundParams, &foundX, &longestWidth, &lastWidth, params](const std::string & value, const int & x, const int & y) { 
         if (x > longestWidth) 
          longestWidth = x; 

         lastWidth = x; 

         GetValueCell(foundX, value, x); 

         CheckParams(foundX, foundParams, value, x, params); 
        }, 
         [&longestWidth, &lastWidth, &foundX, this](const int & row) { 

         if (lastWidth < longestWidth) 
          for (int i = lastWidth + 1; i <= longestWidth; ++i) { 
           auto find = foundX.find(i); 

           if (find != foundX.end()) { 

            find->second->PushValue(""); 
           } 
          } 

        }); 

        sheet.Close(); 
       } 

       if (params->size() < 1) 
        break; 
      } 

      delete sheets; 

      while (foundParams.size() > 0) { 
       params->push_back(*foundParams.begin()); 
       foundParams.erase(foundParams.begin()); 
      } 

     } 

     book.Close(); 

     return true; 
    } 

    return false; 
} 

bool XlsToData::Convert(const std::string & filePath, std::list<SqlParam*>* params) { 
    ExcelFormat::BasicExcel book; 

    if (book.Load(filePath.c_str())) { 
     int sheets = book.GetTotalWorkSheets(); 
     std::list<SqlParam*> foundParams; 

     for (int i = 0; i < sheets; ++i) { 
      ExcelFormat::BasicExcelWorksheet* sheet = book.GetWorksheet(i); 

      std::map<int, SqlParam*> foundX; 

      if (sheet != nullptr) { 
       const int rows = sheet->GetTotalRows(); 
       const int cols = sheet->GetTotalCols(); 

       std::map<int, SqlParam*> foundX; 

       for (int row = 0; row < rows; ++row) { 
        bool willBreak = false; 

        for (int col = 0; col < cols; ++col) { 
         ExcelFormat::BasicExcelCell * cell = sheet->Cell(row, col); 

         if (cell != nullptr) { 
          std::string value = getval(cell); 

          GetValueCell(foundX, value, col); 

          CheckParams(foundX, foundParams, value, col, params); 
         } 

        } 

        if (willBreak) 
         break; 
       } 
      } 
     } 

     while (foundParams.size() > 0) { 
      params->push_back(*foundParams.begin()); 
      foundParams.erase(foundParams.begin()); 
     } 

     book.Close(); 

     return true; 
    } 

    return false; 
} 

我希望能夠抽象方法來打開書籍/張成單一的方法爲遍歷每個單元格的過程。

我已經考慮過可能修改ExcelFormat的源碼和Xlsx I/o的Wrapper類以使用統一的抽象基礎。

請問這是最明智的方式嗎?

這種衝突有沒有設計模式?

我應該實現一個從Excel格式的類繼承的適配器類,然後有Xlsxio包裝和新的適配器類符合新的抽象基地?

或者沒有人有更好的解決方案嗎?

感謝。

編輯:另外,側面說明,我意識到這顯然有很長的方法代碼氣味。我打算用更廣義的算法來重構這個。

回答

0

您是否考慮過使用https://sourceforge.net/projects/xlslib/? 它稍微沒有過時,更便攜。

對於XLSX I/O,如果您需要遍歷所有單元格(包括空單元),則推薦使用xlsxioread_process的XLSXIOREAD_SKIP_NONE標誌。

其餘的我認爲編寫一個通用的基類並不像你說的那樣明顯,因爲庫之間的方法不同。

我的建議是使抽象類儘可能抽象,這意味着你不應該基於任何一個庫,而只是它們的共同屬性。

就我個人而言,我已經放棄.xls支持,因爲這是Microsoft自Office 2007以來不再主動使用的封閉格式。