2017-01-31 5 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?

Метод Цепочка имеет смысл в языках, когда функции существуют как методы внутри области действия объекта. Учитывая API в своем нынешнем состоянии, я остался использовать его как это:

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

Есть ли какие-либо методы, которые я могу использовать в C, чтобы получить ту же текучесть, как и в других языках?

+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++ и другие языки ООП:

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

ли это более читаемым, чем separat 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); 

И нет простого способа реорганизовать эту цепочку в более удобочитаемую.

Обратите внимание, что некоторые из самых древни функций библиотеки 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 * - это выбранный термин в языках ООП, но он имеет общий смысл вне этой области. Я намекнул, что синтаксис цепочки методов не IMHO не переносит большую текучесть. Это только мое мнение, поэтому я, возможно, не в тему. – chqrlie

+0

@Barmar: OP, вероятно, знает, но случайный читатель, программист на C, не может этого сделать. – chqrlie

Смежные вопросы