Factory Patterns & Node.JS

One of the patterns which is very popular in Software Engineering is the Factory Pattern.

This pattern is typically taught in universities using an object-oriented approach (I know I learned it with Java). Unfortunately, the object-oriented pattern doesn’t lend itself well to Javascript (in particular, Node.js). Lets consider an example and how it may be implemented in an object-oriented language like C#, and in Node.js.

We would like to model a factory provider pattern for employee management. A situation or task is given, and the factory is to provide a new instance of an employee suitable to performing the task. Eg: for a broken pipe, a plumber instance will be returned, for a faulty light switch, an electrician instance will be returned.

Object Oriented Approach:

First lets consider C#, we can straight away see that we’ll need something like:

  • EmployeeFactory.cs
  • Employee.cs (interface)
  • Plumber.cs
  • Electrician.cs

We might first new-up the EmployeeFactory, which would have a .getIntsance(<task>) method accepting a task, and returning an object that satisfies the Employee Interface. Sometimes we can avoid newing-up the factory instance by making .getInstance(<task>) a static method. This has the drawback that if choosing the right employee for the task requires sub-methods, these will also have to be static or stored in a singleton util.

Javascript in Node.js:

Javascript actually makes factory pattern a lot easier to implement, but harder to recognize. This is because, in a sense, everything is a factory. What is meant is that in the absence of classical objects, every function (or method) creates a closure for itself as an instance.

Lets take another look at the goals of factories – they aim to separate how something should be created from where it is used, thereby encapsulating the creation logic, and creating a single implementation of object creation (objects created by the factory).

How might we do this in Node.js? Well, we would create an ‘Employee’ folder, and in it have:

  • electrician.js
  • plumber.js
  • index.js

In this case, index.js itself is the factory responsible for creating new instances, and could look something like:

module.exports = function getEmployee(task) {
  if (task === "broken pipe") {
    return require("plumber.js")(task);
  } else if (task === "faulty light switch") {
    return require("electrician.js")(task);
  }
};

Here we pass the task into the employee, but we could just as easily forward any other properties through, such as job-site, or purchase-order-number, etc.

Plumber or electrician files would be written like this to return a new instance each time:

module.exports = function plumber(task) {
  function fixPipes() { 
    // do plumbing
  }
  
  return {
    work: fixPipes
  };
};

Note that we try to avoid using new and this.

Now we can easily use this in our other code in the following way:

var Employee = require("../path/to/Employee");
...
Employee("broken pipe").work(); // assuming 'work' is the standard interface method.

// or
var wireFixer = Employee("faulty light switch");

wireFixer.work();
wireFixer.work();

Strongly typed object-oriented languages like C# or Java with interfaces and generics help to ensure that an employee will always support the methods (.work()) that we will use them for. We don’t get those guarantees with javascript.

Whats good about javascript here, is that the factory doesn’t need to know about the underlying logic of its members. Lets say we need to add a new employee to “manage whole company”, this employee will need to be a singleton (we don’t want to accidentally hire two CEO’s at the same time!). We could easily accomplish this like so:

var ceoInstance; 

module.exports = function ceo(task) { 
  if (ceoInstance) { 
    return ceoInstance;
  }

  return ceoInstance = {
    work: manageTheCompany
  };

  function manageTheCompany() { 
    ... 
  }
};

Adding the logic to create the CEO instance in the factory is identical to creating the plumber instance, which is to say that the factory isn’t responsible for managing singletons (and it shouldn’t be).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: