There are good solutions but I think we need a little bit more of theory
This questions is the best example to use a Factory Pattern
Design patterns can make your code more flexible, more resilient to change and easier to maintain.
Teo, is possible to use Factory Patterns in JavaScript?
Yes, my young Padawan.
But, what is the Factory pattern?
The factory pattern is a creational design pattern, which means it deals with object creation. There are three theoretical types of factory patterns:
- Simple factory
- Factory method
- Abstract factory
Simple Factory is an object which encapsulates the creation of another object. In ES6 it could be a constructor being instantiated by new
in a function and then return the instance like this:
class Player {...}
const PlayerFactory = {
makePlayer: (type, level) => new Player(type, level),
}
In this example makePlayer
returns the instance of the Player
class.
Factory Method defines one method for creating a class instance, which is overridden by subclasses who decide what to return.
In ES6 it could be implemented extending classes because there are no interfaces and using a method to instantiate and object using new
class Dragon {...}
class Snake {...}
class Player {
fightMonster() {
const monster = this.makeMonster()
monster.attack()
}
}
class Warrior extends Player {
makeMonster() {
return new Dragon()
}
}
class Knight extends Player {
makeMonster() {
return new Snake()
}
}
In this example, Player
class call makeMonster
method then Warrior
and Knight
classes override makeMoster
method to return either a Dragon
or a Snake
class instance.
Finally, the Abstract Factory provides an interface for creating families of related or dependent objects without specifying their concrete classes
The interpretation of families
could be like a category or list of classes. In ES6 it can be an instance that encapsulates a group of individual factories with a common goal. It separates the details of implementation of a set of objects from their general usage.
class WinButton {
constructor(options) {
this.name = 'WinButton'
this.options = options
}
}
class LinuxButton {
constructor(v) {
this.name = 'LinuxButton'
this.options = options
}
}
// Mapping names and class definitions
const supportedOS = new Map([
['Windows', WinButton],
['Linux', LinuxButton]
])
// Use a Factory Abstract pattern
const classFactory = (c, v) => {
const maker = supportedOS.get(c)
return new(maker)(v)
}
// Factory a class from a string
const name = 'Windows'
const param = {enabled: true}
const btn = classFactory(name, param)
console.log({btn})
In this final example we can see that the function classFactory
uses the Factory Abstract pattern because instantiate a class from a list of supported OS (Linux or Windows) by setting maker with the constructor of the desired class, in this case WinButton
class.