HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Fluent interface for manipulating employee records

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
manipulatingemployeerecordsinterfaceforfluent

Problem

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
#include
/ 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 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 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_employ

Solution

I would drop the edit function and make add_employee the entry point to the API. I've written a number of fluent APIs in C++ and found that placing the required arguments (e.g., employee name) in the API entry point invaluable. From the usage point of view, something like:

int main(void) {
    Record db;
    init_record(&db);
    add_employee_to(&db, "Bob")
        ->having_salary(2000)
        ->with_id(10202);
    return 0;
}


The goal of the API is to create a new employee and append them, so make that the entry point. If you can't have a valid employee record with a name, then this becomes a first-class parameter of the entry point. Not sure about the requirements, so it may make sense for ID to be a required parameter as well. I also changed the names to make them More Fluent™.

Code Snippets

int main(void) {
    Record db;
    init_record(&db);
    add_employee_to(&db, "Bob")
        ->having_salary(2000)
        ->with_id(10202);
    return 0;
}

Context

StackExchange Code Review Q#6254, answer score: 3

Revisions (0)

No revisions yet.