Why would you mix a factory function with a constructor

I am going through Essential javascript patterns and the factory pattern.

I searched what a factory pattern was from other sources and roughtly speaking it is just like the constructor but you do not have to use the this keyword.

const Car = (model, year, miles) =>{
  const something = 'blah' // rather than, this.something
  return{
    toString:()=> model + " has done " +miles + " miles"
  }
}
var carOne = Car("Honda Civic", 2009, 20000)
console.log(carOne.toString() )

var carTwo = Car(“Ford”, 2009, 20000)
console.log(carTwo.toString() )

So far, I get it. But why do the following

// A constructor for defining new cars
function Car( options ) {
  this.doors = options.doors || 4;
  this.state = options.state || "brand new";
  this.color = options.color || "silver";
}
 
// A constructor for defining new trucks
function Truck( options){
  this.state = options.state || "used";
  this.wheelSize = options.wheelSize || "large";
  this.color = options.color || "blue";
}
// Define a skeleton vehicle factory
function VehicleFactory() {}
VehicleFactory.prototype.vehicleClass = Car;
VehicleFactory.prototype.createVehicle = function ( options ) {
  switch(options.vehicleType){
    case "car":
      this.vehicleClass = Car;
      break;
    case "truck":
      this.vehicleClass = Truck;
      break;
    //defaults to VehicleFactory.prototype.vehicleClass (Car)
  }
  return new this.vehicleClass( options );
};
var carFactory = new VehicleFactory();
var car = carFactory.createVehicle( {
            vehicleType: "car",
            color: "yellow",
            doors: 6 } );
console.log( car instanceof Car );
 
// Outputs: Car object of color "yellow", doors: 6 in a "brand new" state
console.log( car );

We are turing a factory into a class for no reason it seems

What is going on? Why would we do that, even in this case

That example probably just wants to demonstrate how you can wrap constructor functions to return different kinds of objects depending on the arguments… although it’s a bit curious that the factory has itself to be instantiated, where the createVehicle() function alone could do the same.

But indeed, unless the creation of these objects depends on some already existing (e.g. 3rd party) constructor functions, you might actually use Object.create() instead:

const Chicken = {
  fertilize () {
    this.eggs = (this.eggs || 0) + 1
  },

  layEggs () {
    const result = this.eggs || 0
    this.eggs = 0
    return result
  }
}

function createChicken (options) {
  const chicken = Object.create(Chicken)
  return Object.assign(chicken, options)
}

const myChicken = createChicken({eggs: 2})

Using a factory function like this also makes for a more robust API, as the consumer doesn’t have to care whether the returned object is created with new or not – changing this would be a breaking change if you just exposed a constructor function.

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.