有没有更好的办法?循环并继续

时间:2009-11-11 14:58:56

标签: c++ refactoring loops

我维护的代码中有许多功能,它们可以被描述为样板重。以下是样板模式,当使用游标处理DB I / O时,在整个应用程序中重复出现恶心:

if( !RowValue( row, m_InferredTable->YearColumn(), m_InferredTable->YearName(), m_InferredTable->TableName(), value )
        || !IsValidValue( value ) )
    {
        GetNextRow( cursor, m_InferredTable );

        continue;
    }
    else
    {
        value.ChangeType(VT_INT);
        element.SetYear( value.intVal );
    }

事情并非所有这些陈述都是这样处理的内容,这个“元素”对象,“年”专栏等等。我被要求考虑将其缩小甚至超过它已经存在并且我可以想办法去做。我一直在跳过continue语句和各种类的访问器。

编辑:感谢所有评论过的人。这就是我喜欢这个网站的原因。这是一个扩展视图:

while( row != NULL )
{
    Element element;
    value.ClearToZero();
    if( !GetRowValue( row, m_InferredTable->DayColumn(), m_InferredTable->DayName(), m_InferredTable->TableName(), value )
        || !IsValidValue( value ) )
    {
        GetNextRow( cursor, m_InferredTable );

        continue;
    }
    else
    {
        value.ChangeType(VT_INT);
        element.SetDay( value.intVal );
    }

事情继续这样。并非所有从“行”中获取的值都是整数。 while循环中的最后一个子句是“GetNextRow。”

6 个答案:

答案 0 :(得分:4)

好的,从你所说的,你有一个像这样的结构:

while (row!=NULL)  {
    if (!x) {
        GetNextRow();
        continue;
   }
   else {
       SetType(someType);
       SetValue(someValue);
   }
   if (!y) {
       GetNextRow();
       continue;
   }
   else {
       SetType(SomeOtherType);
       SetValue(someOtherValue);
   }
// ...

   GetNextRow();   
}

如果确实如此,除了最后一个之外,我将摆脱所有 GetNextRow个电话。然后我将代码构造成:

while (row != NULL) {
    if (x) {
        SetType(someType);
        SetValue(someValue);
    }
    else if (y) {
        SetType(someOtherType);
        SetValue(SomeOtherValue);
    }
    // ...
    GetNextRow();
}

编辑:另一种可能性是将您的代码编写为for循环:

for (;row!=NULL;GetNextRow()) {
    if (!x) 
        continue;
    SetTypeAndValue();
    if (!y)
        continue;
    SetTypeandValue();
    // ...

由于对GetNextRow的调用现在是循环本身的一部分,我们不必每次都(明确地)调用它 - 循环本身将处理它。下一步(如果你有足够的这些使它值得)将是缩短代码来设置类型和值。一种可能性是使用模板专业化:

// We never use the base template -- it just throws to indicate a problem.
template <class T>
SetValue(T const &value) { 
   throw(something);
}

// Then we provide a template specialization for each type we really use:
template <>
SetValue<int>(int value) {
    SetType(VT_INT);
    SetValue(value);
}

template <>
SetValue<float>(float value) { 
    SetType(VT_FLOAT);
    SetValue(value);
}

这使您可以组合一对调用,将类型和值设置为单个调用。

编辑:就切割处理的简短而言,它取决于 - 如果解析一个列很昂贵(足够关心),你可以简单地嵌套你的条件:

if (x) { 
    SetTypeAndValue();
    if (y) {
        SetTypeAndValue();
        if (z) { 
            SetTypeAndValue();

等等。这样做的主要缺点是如果(如你所说)你在一个循环中有20多个条件,那么它将会非常深入嵌套。既然如此,我可能会认真思考上面给出的基于for循环的版本。

答案 1 :(得分:2)

为什么不做一个完成所有工作的功能?

bool processElement(Element& element, Row* row, int value, Table& m_InferredTable, /*other params*/)
{
    if( !GetRowValue( row, m_InferredTable->DayColumn(), m_InferredTable->DayName(), m_InferredTable->TableName(), value )
            || !IsValidValue( value ) )
    {
            GetNextRow( cursor, m_InferredTable );
            return true;
    }
    else
    {
            value.ChangeType(VT_INT);
            element.SetDay( value.intVal );
    }
    return false;
}

在你的循环中

while (row != NULL)
{
    if (processElement(element, row, value, m_InferredTable))
        continue;
    // other code
}

答案 2 :(得分:0)

为什么不反转你的if-test?

   if (RowValue(row, m_InferredTable->YearColumn(), m_InferredTable->YearName(),  m_InferredTable->TableName(), value ) 
     && IsValidValue( value ))
   {
     value.ChangeType(VT_INT);
     element.SetYear( value.intVal );
   }
   else
   {
     GetNextRow( cursor, m_InferredTable );
   }

答案 3 :(得分:0)

我的本​​能方法是在这里构建一个多态方法,在这种方法中,你最终会做出类似的事情(模块化你的语言和确切的逻辑):

db_cursor cursor;

while(cursor.valid())
{
  if(cursor.data.valid())
  { 
     process();
  }

  cursor.next();
}

db_cursor将是您的不同表类型类继承的基类,子类将实现有效性函数。

答案 4 :(得分:0)

将其移动到模板函数中,模板化元素类型(例如整数),您可以反复调用。使用特征模板改变每种数据类型的行为。

template <typename T> struct ElemTrait<T> {};
template <> struct ElemTrait<int> {
    static inline void set(Val &value, Elem &element) {
        value.ChangeType(VT_INT);
        element.SetYear(value.intVal);
    }
};
// template <> struct ElemTrait<float> { ... };

template <typename T>
void do_stuff( ... ) {
    // ...

    if (!RowValue(row,
        m_InferredTable->YearColumn(),
        m_InferredTable->YearName(),
        m_InferredTable->TableName(), value)
        || !IsValidValue(value)
    ) {
        GetNextRow(cursor, m_InferredTable);
        continue;
    } else {
        ElemTrait<T>::set(value, element);
    }

    // ...
}

答案 5 :(得分:0)

您可以取出所有GetNextRow调用和else子句:

for (row = GetFirstRow () ; row != null ; GetNextRow ())
{
    Element element;
    value.ClearToZero();
    if( !GetRowValue( row, m_InferredTable->DayColumn(), m_MetInferredOutTable->DayName(), m_MetInferredOutTable->TableName(), value )
            || !IsValidValue( value ) )
    {
      continue;
    }

    value.ChangeType(VT_INT);
    element.SetDay( value.intVal );
}