哪种C ++设计方法更易于维护?

时间:2011-10-21 14:30:42

标签: c++ oop design-patterns

目前的规格是:

以宽字符或窄字符数组的形式给定字符串数据,为类提供功能,该类提供数据统计并修改数据。

要求是长期可以维持。

所以我的第一种方法是先将raw char数组编组成字符串,然后只提供一个模板类:

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,那么除了要编写的新派生类之外,它只需要更改前两行代码。

我认为如果我写一个包装类,如1&amp; 3它变得更加繁重,任何封装都被打破,因为我必须允许访问底层。

但是如果我创建一个只有静态函数的类,那么它所做的就是模仿一个命名空间,这个命名空间可以更好地服务于一个非成员的非友元函数。 “stringtools”命名空间。但是我仍然会在整个应用程序中传播原始字符数组的混乱,并且必须执行额外的验证等规范 明确要求上课。

那么最干净,最易维护的方法是什么?

RGDS

4 个答案:

答案 0 :(得分:4)

最好的方法是做类似stl算法的工作。

有一个只接受字符串char / wchart_t开始和结束迭代器的进程算法。这样,您的算法将无缝地用于所有可以在内存中连续的字符串。

答案 1 :(得分:1)

听起来我不喜欢 类,你应该考虑使用完全正常string / wstring数据的通用算法。根据您在统计/修改方面最终需要的内容,您甚至可能不需要编写实际算法,而只需要编写仿函数(例如)std::accumulate

如果您最终需要使用类似BSTR的东西,则需要为BSTR提供迭代器接口。但就个人而言,即使我正在处理COM,我几乎一直都会使用普通字符串实际工作,并且在将它传递给某个COM之前立即转换为BSTR。同样在回程中,一旦我收到BSTR,我就将其转换为普通字符串,并以该形式使用它。从理论上讲,如果你和COM一起工作的话,把事情当作BSTR可能会更快,但是我还没有看到转换为正常字符串的转换成任何接近瓶颈的事情。

答案 2 :(得分:0)

这个问题没有明确说明,你正在过度设计这个问题。

将收集哪些统计数据?将对字符串进行哪些更改?这些字符串有多长?性能是否重要?

为什么不使用简单的解决方案:编写所有统计/字符串更改例程以使用UTF-8(假设这是char s的编码)。如果需要处理UTF-16字符串,请将其转换为UTF-8,调用对其起作用的例程,然后将修改后的字符串转换回UTF-16。 KISS。

编辑:

还有另一个考虑因素:您的算法是否与编码无关(即它是否与字符串的编码无关),即唯一的变量是字符的“宽度”?如果是这种情况,正如parapura所暗示的那样,采用开始和结束迭代器的模板化程序可能是一种选择。

根据您的澄清,听起来好像您的算法目前编码不可知 - 但是既然您提到可维护性,您应该考虑将来是否也会这样做

答案 3 :(得分: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;
    }
}