2016-12-17 61 views
0

假设例如,我有两个函数几乎是完全一样的,这代表了系统的瓶颈,那是这个样子,(要复杂得多):保持代码DRY不牺牲效率

void f1(int s) 
{ 
    for(size_t i = 0, END = m_v.size(); i < END; ++i) 
    { 
     int bin_id = binId(m_v[ i ], s); 
     m_result[ bin_id ] += m_w[ i ]; // 
    } 
} 

void f2(int s) 
{ 
    for(size_t i = 0, END = m_v.size(); i < END; ++i) 
    { 
     int bin_id = binId(m_v[ i ], s); 
     m_result[ bin_id ] += 1.f; // 
    } 
} 

除了您在代码的一行中使用变量或常量之外,所有内容都是相同的。如前所述,假设实际的代码要复杂得多。最好不要将它复制两次,但要有一点不同,因为它需要确保每个区域保持一致。我可以这样做,将它们合并为一个:

void f3(bool use_weight, int s) 
{ 
    if(use_weight) 
    { 
     for(size_t i = 0, END = v.size(); i < END; ++i) 
     { 
      int bin_id = binId(v[ i ], s); 
      result[ bin_id ] += m_w[ i ]; // 
     } 
    } 
    else 
    { 
     for(size_t i = 0, END = v.size(); i < END; ++i) 
     { 
      int bin_id = binId(v[ i ], s); 
      result[ bin_id ] += 1.f; // 
     } 
    } 
} 

但是,这仍然是重复的代码,只是在一个单一的功能。我们能做到这一点,但它会给性能越差:

void f3(bool use_weight, int s) 
{ 
    for(size_t i = 0, END = v.size(); i < END; ++i) 
    { 
     int bin_id = binId(v[ i ], s); 
     if(use_weight) 
     { 
      result[ bin_id ] += m_w[ i ]; // 
     } 
     else 
     { 
      result[ bin_id += 1.f; // 
     } 
    } 
} 

,并且调用代码如下所示:

bool use_weight = something.use_weight(); 
const int N = very_large_number; 
for(int s = 0; s < N; ++s) 
{ 
    f3(use_weight, s); 
} 

同样,假定代码要复杂得多,使得F3,例如是实际上重复了很多逻辑。

+2

将代码分解成一个'inline'函数,它接受一个参数,并传递一个变量或一个常量应该避免代码重复,并让编译器每次发出适当的代码。 –

+0

你会传递'bool'作为模板参数吗? – qxz

+0

您可以使用lambdas代替两个变体中的代码,并在循环之前将相应的回调设置为变量。但是如果这是一个瓶颈功能,函数调用开销可能会很繁琐。 – Barmar

回答

1

老实说,有时候优化代码的可重用性往往会走出门外,但在你的例子中,它可能会更好地利用多态性。类和函数应该接受他们正在处理的参数,而不是工作成员变量。制作一个'超级'功能或者'全力以赴'的班级通常是一个错误。随着时间的推移,这些类和函数会越来越臃肿。

因此,代码将理想地使用接口,并且需要的解析器将被注入。 :)

var parser1 = new HotSauceParser(); 
parser.parse(arrayData); 

var parser2 = new WeightParser(); 
parser2.setWeights(m_w); // in many langages you can chain this. 
parser.parse(arrayData); 

这是继Single responsibility principle,它容易测试。然后你可以编写一个类来决定何时使用一个类或另一个类。如何解析的逻辑被封装在解析器本身中。

就效率而言,通常如果你解析一个数组,那么性能问题是关于BIG数组是多少,你是否必须遍历整个结构。

只要注意'干掉你的代码,就很容易干扰你的代码,并陷入常见的陷阱,比如过度使用继承和/或用'Feature Envy'创建类和函数。

您可能想查看Clean Code book和S.O.L.I.D.