The Factory Pattern in JS ES6

I’m trying to get the most out of all the new things in ES6 (ES2015). And I’m writing a new library where I need a Factory. So I wondered how I could take advantage of all the new stuff to do this, whilst not forgetting that all ES5 continues to be valid and useful side-by-side to ES6.

I researched and googled it because there are very smart coders out there that usually ask this type of questions, before I do, and have smart answers. It was quite difficult to get results, and I couldn’t find any that combined both areas: ES6 + Factory-Pattern. Maybe it’s because nobody has written about it or just because both areas have so many references on their own that popular posts about other technologies or ES5 appear at the top results and new posts are yet to climb up the rankings.

So I had to come up with something on my own. But before diving into the subject, we need to have a common understanding of what is that thing of a “Factory Pattern”. I recommend that you read a post from Rob Dodson, which brings light to the topic. You’ll find he talks about 3 conceptual Factory Patterns:

  • Simple Factory
  • Factory Method
  • Abstract Factory

“A simple factory is an object which encapsulates the creation of another object”. In ES6 it could be the constructor being instatiated by “new”.

//Definition of class
class User {
    constructor(typeOfUser){
this._canEditEverything = false;
        if (typeOfUser === "administrator") {               
this._canEditEverything = true;
}
}
    get canEditEverything() { return this._canEditEverything; }
}
//Instatiation
let u1 = new User("normalGuy");
let u2 = new User("administrator");

The simple factory is, as you can see, very simple. It only applies to one class. Good enough for many situations.

Factory Method defines one method, createThing for instance, which is overriden by subclasses who decide what to return. The Factories and Products must conform to interfaces for clients to be able to use them.”

Continuing with our use of “new” instead of creating new methods, in ES6 it could be implemented extending classes:

//Class
class User {
constructor(){
this._canEditEverything = false;
}
    get canEditEverything() { return this._canEditEverything; }
}
//Sub-class
class Administrator extends User {
constructor() {
super();
this._canEditEverything = true;
}
}
//Instatiation
let u2 = new Administrator();
u2.canEditEverything; //true

“The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.”

The important point here is the word “families”. Continuing with our example it could be implemented in ES6 as an “interface” (a class) and many “concrete classes” (sub-classes). In TypeScript (as in c#) the interface exists as a definition (without any implementation) and classes implement it. But in JS (including ES6) they don’t, that’s why we use a class and sub-classes that extend it. So we could have the sub-classes “Administrator”, “Editor”, “Publisher”, etc.

Registering concrete objects at run-time

So far so good, but I needed something more useful. I needed:

  • A Factory that allows the registration of sub-classes at run-time. In my case this is necessary as I need to allow coders to create new types of Users and the app to make them available in the user-interface,
  • A Factory available to all the instances of the user-control with all the previously registered new types of Users. This is simple, it needs to be a Singleton.

So I created an ES6 Class with static methods to register and to create instances of the classes. Something like this:

class Factory {
constructor() {
}
    static register(clazzname, clazz) {
if ((!Factory._registeredTypes.has(clazzname) &&
clazz.prototype instanceof User)) {
            Factory._registeredTypes.set(clazzname, clazz);
...
        } else { ... }
    }
    static create(clazzname, ...options) {
        if (!Factory._registeredTypes.has(clazzname)) {
console.error("!!!");
return null;
}
        let clazz = this._registeredTypes.get(clazzname);
let instance = new clazz(...options);
return instance;
    }
}
Factory._registeredTypes = new Map();

Look at two things: (1) it uses “static” methods and (2) it binds a “Map” to a property at the bottom. In ES6 you can have static methods (that do not require an instatiation to be used, that won’t be available if instatiated and that do not have access to instance this properties) but there are not “static properties” in the specification. Thus we have to create them in (2).

This works ok. And some of you might find it as a natural implementantion. But I don’t. I don’t like the fact that it looks like it can be instatiated. Or you could say, forget about static methods and instatiate it in your library, just add the logic to make it a Singleton. Yes, that could work as well.

It might be a matter of style, but I prefer an object to a class or function for this case. So finally I simply used an object:

const Factory = {
    registeredTypes: new Map(),
    register(clazzname, clazz) {
if (!(Factory.registeredTypes.has(clazzname) &&
clazz.prototype instanceof User)) {
            Factory._registeredTypes.set(clazzname, clazz);
        } else { ... }
},
    create(clazzname, ...options) {
        if (!Factory.registeredTypes.has(clazzname)) {
console.error("!!!");
return null;
}
        let clazz = this.registeredTypes.get(clazzName);
let instance = new clazz(...options);
return instance;
    }
}

That is, after 2 days of figuring out how to implement it in my new ES6 library I came out with a quite standard solution!

I invite you to share your ideas or implementation taking the previous examples as a contribution. How do/would you do it?

Thanks for reading and giving your opinion!