2011-10-21 20 views
4

當前規範是:哪種C++設計方法更易於維護?

給定字符串數據以寬或窄字符數組的形式寫入提供數據統計信息並修改數據的類的功能。

要求是要長期維護。

所以我的第一個方法是要求原始字符數組來之前整理成字符串,然後只是提供了一個模板類:

template<class T> 
class MyString 
{ 
private: 
    T _data; 
public: 
    MyString(T& input) { _data = input; }; 
    size_t doSomeWork() { //assume T is of type basic_string<...> and use iterators }; 

}; 


//Use 
const char* data = "zyx"; 
string blahblah(data); 
MyString<string> abc(blahblah); 
abc.doSomeWork(); 

或靜態成員函數:

class StringTools 
{ 
public: 
    static size_t doWork(const char*) {} 
    static size_t doWork(const wchar_t*) {} 
}; 

//used like so: 
const char* data = "hallo kitty"; 
cout << StringTools::doWork(data); 

,或者使用戰略模式:

class MyString 
{ 
protected: 
    MyStringBase(); 
public: 
    virtual ~MyStringBase();  
    virtual size_t doWork() = 0; 
}; 

class MyStringCharArray : public MyString 
{ 
protected: 
    char* _data; 
public: 
    MyStringCharArray(const char* input) : MyString() { } 
    virtual size_t doWork() {...}; 
}; 

//so it would be used like so 
const char* blah = "blah"; 
MyString* str = new MyStringCharArray(blah); 
cout << str->doWork(); 
delete str; 

然後在未來,如果對於某些上帝遺棄的理由我切換到BStr's,那麼它只需要除了正在寫入的新派生類之外,還要更改前兩行代碼。

我認爲,如果我寫一個包裝類,如1 & 3它變得更加沉重和任何封裝被打破,因爲我必須允許訪問底層。

但是,如果我創建一個只有靜態函數的類,那麼它所做的就是模仿一個名稱空間,它可以更好地服務於封裝在 「stringtools」命名空間下的一些非成員非朋友函數。但是,我仍然會在整個應用程序中傳播原始字符數組的混亂,並且額外的驗證將不得不執行等,並明確要求提供一個類。

那麼最乾淨和最易維護的方法是什麼?

RGDS

回答

4

最好的辦法是做類似的算法做STL。

有一個只接受字符串char/wchart_t開始和結束迭代器的進程算法。這樣你的算法就可以無縫地處理所有可以在內存中連續的字符串。

+0

您也可以提供一個覆蓋,需要一個容器,並使用調用爲了更簡單的使用,在內部使用'.begin()'和'.end()'。此外,這將適用於任何類型的迭代器的所有字符串,他們不必是連續的。 –

0

該問題未被詳細說明,而您正在對此進行過度設計。

會收集什麼樣的統計數據?對字符串做出什麼樣的改變?這些琴絃要多久?績效是否重要?

爲什麼不用一個簡單的解決方案:寫所有的統計/字符串更改例程以使用UTF-8(假設這是您的char的編碼)。如果您需要使用UTF-16字符串,請將其轉換爲UTF-8,然後調用對其適用的例程,然後將修改過的字符串轉換回UTF-16。吻。

編輯:

還有另一種考慮:你的算法編碼無關的(即是它的獨立字符串的編碼),即是唯一的變量字符的「寬度」?如果是這樣的話,像parapura建議的那樣,採用一個開始和結束迭代器的模板化例程可能是一種選擇。

根據您的澄清,這聽起來好像你的算法目前是不可知的編碼 - 但既然你提到的可維護性,你應該考慮這是否也將在未來成爲真正的

+0

我寧願推薦UTF-32,那麼他只需要寫轉換(或使用ICU),而不必再擔心。如果使用非西方語言,使用UTF-8會有問題。 – RedX

+0

將在當前規範中收集的統計信息只是子字符串出現的次數,並且可能發生的修改只是替換所述子字符串。性能確實很重要,但扮演着可維護性和可讀性的第三把手 – Pepe

+0

@RedX:我相信你會把UTF-8與單字節8位編碼(如ISO 8859-1)混淆起來。雖然後者確實只支持西方語言,但UTF-8編碼所有可能的Unicode代碼點 - 即UTF-32可編碼的所有代碼點。 –

1

這聽起來好像代替a class,您應該考慮通用算法,這些算法對完全正常的數據進行操作。根據您最終需要的統計/修改方式,您可能甚至不需要編寫實際算法,而只需要應用(例如)std::accumulate的函子。

如果你最終需要使用類似於BSTR的東西,你需要爲BSTR提供一個迭代器接口。然而,就個人而言,即使在我處理COM時,我傾向於在幾乎所有時間都會使用正常字符串工作,並且在將它傳遞給某個COM事物之前立即轉換爲BSTR。同樣,在回程中,只要我收到BSTR,我將它轉換爲普通字符串,並以此形式處理它。從理論上講,如果你用COM處理COM,可能會更快地將其作爲BSTRs,但我還沒有看到正常字符串的轉換變成了接近瓶頸的任何東西。

0

好吧,我已經採取了你所說的一切,我已經從規範中分離出了算法。模仿STL算法與迭代器一起工作;而規範要求的「MyClass」封裝了領域知識。

這是怎麼看待你們?

先關算法:

/* 
MyLib 
--------------- 
Methods: 
countOccurances() 
    - given the iterator pairs for two either contiguous areas of memory or containers 
    - counts the number of times the second (needle) occurs in the first (haystack) 
    - returns the count 

replaceOccurances() 
    - same as countOccurances except when a sequence has been matched it is replaced 
     by the replacement needle which must be the same length 

*/ 

template<class fwdIt> 
size_t countOccurances(fwdIt haystackFront, fwdIt haystackEnd, 
           fwdIt needleFront, fwdIt needleEnd) 
{ 
    size_t lengthOfNeedle = std::distance(needleFront,needleEnd); 
    size_t lengthOfHaystack = std::distance(haystackFront,haystackEnd); 
    size_t count = 0; 

    while(true) 
    { 
     //find the needle 
     fwdIt tempIT1 = haystackFront, tempIT2 = needleFront; 
     while(true) 
     { 
      if(tempIT2 == needleEnd) 
      { 
       haystackFront += lengthOfNeedle; 
       lengthOfHaystack -= lengthOfNeedle; 
       count++; 
       break; 
      } 
      else if(*tempIT1 != *tempIT2) 
      { 
       break; 
      } 
      tempIT1++; tempIT2++; 
     } 
     if(lengthOfNeedle <= lengthOfHaystack) 
     { 
      ++haystackFront; 
      --lengthOfHaystack; 
     } 
     else 
     { 
      break; 
     } 
    } 
    return count; 
} 



template<class fwdIt> 
size_t replaceOccurances(fwdIt haystackFront, fwdIt haystackEnd, 
           fwdIt needleFront, fwdIt needleEnd, 
           fwdIt replacementFront, fwdIt replacementEnd) 
{ 
    //The needle and its replacement must be the same length, 
    //this method cannot be reponsible for growing a container it doesn't own. 
    if(std::distance(needleFront, needleEnd) != std::distance(replacementFront, replacementEnd)) 
     throw exception("The needle and its replacement are not the same length"); 

    size_t lengthOfNeedle = std::distance(needleFront,needleEnd); 
    size_t lengthOfHaystack = std::distance(haystackFront,haystackEnd); 
    size_t count = 0; 

    while(true) 
    { 
     //find the needle 
     fwdIt tempIT1 = haystackFront, tempIT2 = needleFront; 
     while(true) 
     { 
      if(tempIT2 == needleEnd) 
      { 
       //replace the needle 
       for(fwdIt tempIT3 = replacementFront; 
        haystackFront != tempIT1, tempIT3 != replacementEnd; 
        haystackFront++, tempIT3++) 
       { 
        *haystackFront = *tempIT3; 
       } 
       count++; 
       break; 
      } 
      else if(*tempIT1 != *tempIT2) 
      { 
       break; 
      } 
      tempIT1++; tempIT2++; 
     } 
     if(lengthOfNeedle <= lengthOfHaystack) 
     { 
      ++haystackFront; 
      --lengthOfHaystack; 
     } 
     else 
     { 
      break; 
     } 
    } 
    return count; 
} 

現在MyClass的

class MyClass 
{ 
public: 
    static size_t getMyCount(std::string& sInput); 
    static size_t getMyCount(std::wstring& sInput); 
    static size_t replaceMyWithMY(std::string& sInput); 
    static size_t replaceMyWithMY(std::wstring& sInput); 


protected: 
    static std::string _narrowNeedle; 
    static std::wstring _wideNeedle; 
    static std::string _narrowReplacementNeedle; 
    static std::wstring _wideReplacementNeedle; 

    template<class T> 
    static size_t _PerformStringOperation(T& sInput, T& sNeedle, bool replace = false, T& sReplacementNeedle = T()) 
    { 
     try 
     { 
      if(replace) 
      { 

       return replaceOccurances( sInput.begin(), sInput.end(), 
              sNeedle.begin(), sNeedle.end(), 
              sReplacementNeedle.begin(), sReplacementNeedle.end()); 
      } 
      else 
      { 
       return countOccurances(sInput.begin(), sInput.end(), 
             sNeedle.begin(), sNeedle.end()); 
      } 
     } 
     catch(MYException& e) 
     { 
      clog << "MyClass::_PerformStringOperation() - could not perform operation" << endl; 
      clog << e.what(); 
      throw; 
     } 
     catch(exception& e) 
     { 
      clog << "MyClass::_PerformStringOperation() - Something more fundemental went wrong" << endl; 
      clog << e.what(); 
      throw; 
     } 
    } 
}; 

和伴隨CPP

std::string MyClass::_narrowNeedle("My"); 
std::wstring MyClass::_wideNeedle = std::wstring(L"My"); 
std::string MyClass::_narrowReplacementNeedle = std::string("MY"); 
std::wstring MyClass::_wideReplacementNeedle = std::wstring(L"MY"); 

size_t MyClass::getNiCount(std::string& sInput) 
{ 
    try 
    { 
     return _PerformStringOperation(sInput,_narrowNeedle); 
    } 
    catch(...) 
    { 
     throw; 
    }   
} 

size_t MyClass::getNiCount(std::wstring& sInput) 
{ 
    try 
    { 
     return _PerformStringOperation(sInput,_wideNeedle); 
    } 
    catch(...) 
    { 
     throw; 
    } 
} 

size_t MyClass::replaceNiWith(std::string& sInput) 
{ 
    try 
    { 
     return _PerformStringOperation(sInput,_narrowNeedle,true,_narrowReplacementNeedle); 
    } 
    catch(...) 
    { 
     throw; 
    } 
} 

size_t MyClass::replaceNiWith(std::wstring& sInput) 
{ 
    try 
    { 
     return _PerformStringOperation(sInput,_wideNeedle,true,_wideReplacementNeedle); 
    } 
    catch(...) 
    { 
     throw; 
    } 
}