2009-11-11 77 views
2

我所维护的代码中有许多函数,它们可能会被描述为样板重。这里是一个与游标处理数据库I/O时,重复整个应用程序的广告恶心的样板模式:有没有更好的方法? While循环并继续

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

的事情是不是所有的这些陈述是这样处理整数的,这个“元素”的对象, “年”专栏等。我被要求比现在更凝结它,我想不出一种办法。我继续跳过继续声明和各个类的访问器。

编辑:感谢所有那些评论。这就是为什么我喜欢这个网站。这里是一个扩大视图:

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”。

+0

你能比后一个例子多的话,所以我们可以看到什么是固定的,哪些更容易改变? – tragomaskhalos 2009-11-11 15:02:16

+0

我们需要看到更多的结构......这显然是一个循环中的一个子句,但是在一个循环中有多少个这样的子句?每个测试(如果)不同? – 2009-11-11 15:04:26

+0

在目前的形式下,很难理解这个问题。为什么有一个“else”分支,如果真正的分支以“continue”结尾?周期内的if后面还有别的东西吗?该周期在哪里? – AnT 2009-11-11 15:07:20

回答

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 (;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循环的版本。

+0

所以,只要说如果我的一个列返回一个无效值只是继续解析所有的列值,最后放弃行的条目,然后继续到下一行?谢谢。 – wheaties 2009-11-11 15:40:51

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

您遗漏了continue语句。这是这里的一大悬念 - 如何获得样板代码以继续循环。 – mskfisher 2009-11-11 15:04:47

+0

“继续”的需要意味着这是循环中许多子句中的一个。我们仍在等待OP的确认,但这听起来像是一个继续执行的大案例声明。 – 2009-11-11 15:08:01

+0

我希望这不是一个大案例陈述。然而,是的,继续是杀死它。如果从其中一列取得的值无效,则continue将导致循环转到查询的下一行。 – wheaties 2009-11-11 15:27:01

0

我本能的做法是在这里建立一个多态的方法,在那里你最终风做这样的事情(模数你的语言和详细的逻辑):

db_cursor cursor; 

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

    cursor.next(); 
} 

db_cursor将是一个基类,你不同的表类型继承自子类,并且子类将实现有效性函数。

+0

如果游标和行对象来自第三方API,该怎么办? – wheaties 2009-11-11 15:22:10

+0

将它们包装在我自己的对象中以实现通用接口。这将是混乱的,你将不得不小心钻石继承问题(取决于),但从长远来看它会更干净。 – 2009-11-11 15:31:53

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

    // ... 
} 
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); 
} 
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 
} 
+0

我需要为每个我想要的值创建一个函数,对吗?并非所有值都是整数。有日,年,小时,另加24种其他类型。该死的我想念反思。 – wheaties 2009-11-11 15:44:11

+0

你可以使它成为处理所有类型的模板函数... – Inverse 2009-11-11 16:02:13

+0

@反向:每种类型在'else'子句中可能都有它自己的唯一代码,所以模板在这里可能没有帮助。函数指针也许? – Skizz 2009-11-11 16:49:29