Factories

Factories are objects which create your objects. They are useful in a number of circumstances:

  • When your language is a poorly designed trash fire (chiefly C++), and compilers cannot agree on how creating an object is supposed to work.
  • When creating an object may require or allow additional context now or in the future.
  • When object creation needs to support versioning.

In some cases this is known as the Builder Pattern. Here is an example of a factory using the builder pattern:

thing_builder_t tb;
tb_start(tb);
tb_set_int(tb, tbPort, 8080); /* using a generic setter */

thing_t* obj = thing_create(tb);
/* fun stuff */
thing_destroy(obj);

Changing the parameters to a function can be a tricky proposition. However you can use the rest of the immortal ABI doctrine against the factory--since it's just an object with its own functions that can be added or removed without breaking anything.

We also have a tb_start function defined here. That could do any number of things:

  • Embed the size of thing_builder_t as we understand it at compile time (the Microsoft method)
  • Embed a serial number as we understand it at compile time
  • Embed a string identifier that we knew at compile time

Case Study: CLAP

The CLAP audio standard makes heavy use of the factory pattern and string identifiers. Factories are also used to produce other factories; with the exception of the "main" entry point to kick off access to the API.

It works a bit like this:

  1. You call an entry point function like clap_init
  2. You provide a string representing the version of the API your program speaks
  3. It returns nil or a reference to the plugin factory
  4. Further features repeat steps 2 and 3, but are requests made against the plugin factory instead.

Here is a trivial example in C:

notclap_t* = notclap_entry("com.example.not-clap/1");
if (notclap_t == NULL) goto failed;

notclap_cat_petter_t* =
   notclap_t->get_plugin(notclap_t, "com.example.not-clap.cat-petter/1");
/* ... */

return 0
failed:
fprintf(stderr, "");
return 1

This looks a bit verbose because we are using C code. Better languages (Nim) allow you to pretty this up.