我维护的代码中有许多功能,它们可以被描述为样板重。以下是样板模式,当使用游标处理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。”
答案 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 );
}