Skip to main content
edited tags; edited title
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473

Fluent interface design pattern in Cfor manipulating employee records

Tweeted twitter.com/#!/StackCodeReview/status/139710459426250752
Source Link
otto
  • 277
  • 2
  • 6

Fluent interface design pattern in C

I wanted to try experimenting with fluent interface design in the C programming language. That's why I wanted to ask you, Dear Code Review users, comments on the way I have implement this simple employee record interface.

Please note that for maximum simplicity I am resorting to as simple data structures as possible.

#include <stdio.h>
#include <assert.h>
/* if this weren't just an example I'd make a linked list */
#define MAX_EMPLOYEE_COUNT 10

/* global this pointer, there is no way around this */
void* this;

typedef struct Employee {
    struct Employee* (*set_salary)(int);
    struct Employee* (*set_employee_id)(int);
    char* name;
    int salary;
    int employee_id;
} Employee;

Employee* do_set_salary(int s)
{
    ((Employee*)this)->salary = s;
    return this;
}

Employee* do_set_employee_id(int id)
{
    ((Employee*)this)->employee_id = id;
    return this;
}

typedef struct Record {
    Employee* (*add_employee)(char*);
    Employee employees[MAX_EMPLOYEE_COUNT];
    int cnt;
} Record;

Employee* do_add_employee(char *n)
{
    Record* this_record = (Record*)this;
    assert(this_record->cnt < MAX_EMPLOYEE_COUNT);
    this_record->employees[this_record->cnt].set_salary = do_set_salary;
    this_record->employees[this_record->cnt].set_employee_id = 
        do_set_employee_id;
    this_record->employees[this_record->cnt].name = n;
    this = &this_record->employees[this_record->cnt];
    this_record->cnt++;
    return this;
}

void init_record(Record* r)
{
    r->cnt = 0;
    r->add_employee = do_add_employee;
}

Record* edit(Record* r)
{
    this = r;
    return r;
}

void print_record(Record* r)
{
    int i;
    for (i = 0; i < r->cnt; i++) {
        printf("%s, salary %d, id %d\n",
               r->employees[i].name,
               r->employees[i].salary,
               r->employees[i].employee_id);
    }
}

int main(void)
{
    Record record;
    init_record(&record);

    /* behold, fluent interface design! */
    edit(&record)->
        add_employee("Alice")->
        set_salary(1500)->
        set_employee_id(10201);

    edit(&record)->
        add_employee("Bob")->
        set_salary(2000)->
        set_employee_id(10202);

    print_record(&record);

    return 0;
}