代码正交性的一种实现

《unix编程艺术》里面讲到在写代码时尽可能的让代码保持正交性, 但是其实在有些情况下正交性也不是这么容易达到的, 下面举例两个函数, 虽然功能不是很实用, 但是表现的现象在项目中还是经常会碰到的:

int sum_a(const int a[], const int b[], int cnt)
{
int i;
int sum;

sum = 0;

for (i = 0; i < cnt; i++) /*--------------------------line1--------------------------*/ sum += a[i] + b[i]; /*--------------------------line2--------------------------*/ return sum; } int sum_b(const int a[], const int b[], int cnt) { int i; int sum; sum = 0; for (i = 0; i < cnt; i++) /*--------------------------line1--------------------------*/ sum += a[i] / 2 + b[i] / 2; /*--------------------------line2--------------------------*/ return sum; }

从上面可以看到其实这两个函数从结果上来看做的完全不同的事, 但是其接口是一样的, 甚至连大部分代码也是一样的, 最关键的是他们不一样的代码是在line1与line2之间, 这样便不可以把line1之上的代码封装一个函数,因为line1之上的代码与line2之下的代码是有很强的关联性的. 因此我惟一能想到的还是回调函数. 将代码改为如下:

static int handler_a(int a, int b)
{
return a + b;
}

static int handler_b(int a, int b)
{
return a / 2 + b / 2;
}

static int do_sum(const int a[], const int b[], int cnt, int (*handler)(int a, int b))
{
int i;
int sum;

assert(handler);

sum = 0;
for (i = 0; i < cnt; i++) sum += handler(a[i], b[i]); return sum; } int sum_a(const int a[], const int b[], int cnt) { return do_sum(a, b, cnt, handler_a); } int sum_b(const int a[], const int b[], int cnt) { return do_sum(a, b, cnt, handler_b); }

从上面来看改为了正交性之后其实通用性更强, 如果有很多类似sum_a, sum_b之类的函数的情况下, 代码量会明显降低, 但是如果如例子所示只有sum_a, sum_b函数的话, 这么做代码将明显增多, 由代码行数与bug成正比关系得出这其实是不划算的, 另外这种做法完全依赖于编译的优化能力, 如果编译器不进行优化的话在调用handler函数里会压栈很频繁, 对于执行效率来说这么做是不可取的, 幸运的是我测试了几次发现编译器对于这种函数指针的调用的会优化的, 尤其是当函数指针传参为常量的情下.

另外可以看出函数的正交性其实是有一个度的, 这个度没有一个固定标准, 只能靠自己的经验去衡量取得最佳值.



评论

  1. 我看了一下,对我还是有帮助的。
    我觉得C语言作为一个中级语言,做到这种程度已经不错了,我想不出其他的方法了。

  2. @likeyiyy 其实用类似宏的方式也是可以达到这种效果的,而且可以不依赖编译器的优化能力, 他是他破坏了封装性。所以被抛弃了。

发表评论