在C语言中没有语法技巧可以实现像其他语言中使用的方法链。在C语言中,您需要编写单独的函数调用,并将对象指针传递给每个函数:
Widget *w = getWidget();
widgetSetWidth(w, 640);
widgetSetHeight(w, 480);
widgetSetTitle(w, "Sample widget");
widgetSetPosition(w, 0, 0);
在C++和其他面向对象编程语言中,同样可以使用方法调用来实现相同的功能:
Widget *w = getWidget();
w->SetWidth(640);
w->SetHeight(480);
w->SetTitle("Sample widget");
w->SetPosition(0, 0);
使用上述API,并假设每个方法都返回this
对象,方法链语法如下:
getWidget()->SetWidth(640)->SetHeight(480)->SetTitle("Sample widget")->SetPosition(0, 0);
无论这种方式是否比分开的语句更易读取,都是一种口味和本地编码约定的问题。个人认为这种方式很笨重且难以阅读。从代码生成的角度来看,有一个小优势:对象指针不需要从局部变量重新加载以进行下一次调用。这种微小的优化几乎无法证明链式语法的合理性。
一些程序员试图通过以下方式使其更易于接受:
getWidget()
-> SetWidth(640)
-> SetHeight(480)
-> SetTitle("Sample widget")
-> SetPosition(0, 0);
再次,这是一种品味和编码约定的问题...但C语言等效代码看起来确实很笨拙:
Widget *w = widgetSetPosition(widgetSetTitle(widgetSetHeight(widgetSetWidth(getWidget(), 640), 480), "Sample widget"), 0, 0);
没有简单的方法可以将这个链条重新组织成更易读的形式。
请注意,一些最古老的C库函数也可以链接在一起:
const char *hello = "Hello";
const char *world = "World";
char buf[200];
strcpy(buf, hello);
strcat(buf, " ");
strcat(buf, world);
strcat(buf, "\n");
可以重新组织成:
strcat(strcat(strcat(strcpy(buf, hello), " "), world), "\n");
但更加安全和受欢迎的方法是这样的:
snprintf(buf, sizeof buf, "%s %s\n", hello, world);
更多相关信息,请参阅:
Marco Pivetta (Ocramius):不良的流畅接口
请注意,如果C对象具有这些调用的函数指针成员,则仍然可以使用上述所有语法,但对象指针仍必须作为参数传递。函数指针通常分组在一个结构中,该结构的指针存储在对象中,模仿C++虚拟方法的实现,使语法稍微繁重一些:
Widget *w = getWidget();
w->m->SetWidth(w, 640);
w->m->SetHeight(w, 480);
w->m->SetTitle(w, "Sample widget");
w->m->SetPosition(w, 0, 0);
链接这些方法也是可能的,但没有实际收益。
最后,应该注意到方法链不允许显式错误传播。在使用链式编程习惯的面向对象编程语言中,可以抛出异常以更或多或少可接受的方式信号化错误。在 C 中,处理错误的惯用方式是返回错误状态,这与返回对象指针相冲突。
因此,除非保证方法一定成功,否则建议不要使用方法链,而是执行迭代测试。
Widget *w = getWidget();
if (SetWidth(w, 640)
|| SetHeight(w, 480)
|| SetTitle(w, "Sample widget")
|| SetPosition(w, 0, 0)) {
}