2017-01-31 33 views
3

有一个现有的C API,看起来像这样:如何使C中的方法链接流畅?

//data 
typedef struct {int properties;} Widget; 

//interface 
Widget* SetWidth(Widget *const w, int width){ 
    // ... 
    return w; 
} 
Widget* SetHeight(Widget *const w, int height){ 
    // ... 
    return w; 
} 
Widget* SetTitle(Widget *const w, char* title){ 
    // ... 
    return w; 
} 
Widget* SetPosition(Widget *const w, int x, int y){ 
    // ... 
    return w; 
} 

第一个参数始终是一个指针实例和改造实例的功能总是返回它作为一个指针。

我认为这样做是为了支持某种Method Chaining

方法在函数作为对象范围内的方法存在时,链接对语言有意义。

int main(void) { 
    Widget w; 
    SetPosition(SetTitle(SetHeight(SetWidth(&w,400),600),"title"),0,0); 
} 

有没有我可以在C使用得到同样的流动性在其他语言中的任何技术:鉴于其当前状态的API,我使用它像这样离开?

+1

不是。流体接口通常只存在于OO语言中。 – Barmar

+1

这在C中没有多大用处,原因有二:一,没有例外。返回值通常用于指示成功或失败。二,手动内存管理,没有RAII。 – EOF

+0

C没有方法。它有功能。你的问题没有意义。 – EJP

回答

3

C语言中没有任何语法技巧来实现方法链接,这可能与其他一些语言中使用的方法相同。在C中,你会写分开的函数调用,传递对象指针到每个功能:

Widget *w = getWidget(); 
widgetSetWidth(w, 640); 
widgetSetHeight(w, 480); 
widgetSetTitle(w, "Sample widget"); 
widgetSetPosition(w, 0, 0); 

同样可以完成与方法在C++调用和其它OOP语言:

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

这是否是比分隔符更易读e声明是品味和本地编码惯例的问题。我个人觉得它很麻烦,很难阅读。代码生成方面有一个小优点:对象指针不需要从下一次调用的本地变量中重新加载。这种微小的优化很难证明链式语法的正确性。

一些程序员试图使它更可口这样:

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

而且没有简单的方法将这个链条重新组织成更具可读性的链条。

需要注意的是一些最ANCIEN 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): Fluent Interfaces are Evil

还要注意的是,如果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); 

链接这些也是可能的,但对于没有真正的获得。

+2

我想他知道流利的界面在其他语言中的样子。问题的关键是如何在C中获得类似的东西。这一切似乎只是一种说不出来的冗长的方式。 – Barmar

+0

@Barmar:* fluid *是OOP语言中的选定术语,但它具有此范围之外的通用含义。我暗示说,方法链接语法不会带来很多流动性。这只是我的看法,所以我可能会脱离主题。 – chqrlie

+0

@Barmar:OP可能知道,但一个C程序员可能不会。 – chqrlie