1

I want to use factory design pattern in my application and use of some of its benefits such as readability, flexibility, scalability, encapsulation and correct binding of "this" operator" during development. As my application generates html code in loading of my webpage, the performance and memory usage of creating objects is important in my case. Please take a look at the following example;

// Factory Design with Delegation
const car = function( color ) 
{
 const CarPrototype = function( color )
 {
  const carPrototype = {};
  
  carPrototype.color = color;
  // Private function
  function internal()
  {
   console.log( "internal" );
   // ...
  }
  
  // Public function
  carPrototype.gas = function()
  {
   internal();
   // ...
  }
  
  carPrototype.brake = function()
  {
   // ...
  }
  
  return carPrototype;
 }
 return Object.create( CarPrototype( color ) );
}

// Traditional constructor function
const Car = function( color )
{
 this.color = color;
 // ...
}

Car.prototype.internal = function()
{
 console.log( "internal" );
 // ...
}

Car.prototype.gas = function()
{
 this.internal();
 // ...
}

Car.prototype.brake = function()
{
 // ...
}


function myFunction()
{

const mazdaF = car( "red" );

const mazdaT = new Car( "red" );
 
console.log( mazdaF, mazdaT );

}
<html>
  <head></head>
  <body onload="myFunction()">
  </body>
</html>

The result of running the above code is shown below.

enter image description here

In addition, performance test result is shown here Performance result.

I want to know whether I am using a correct pattern for my case or not. In case, what should I do to improve performance?

UPDATE:

Now I am a little confused about the factory pattern above. I think when I use Object.create( CarPrototype( color ) ), I am creating a totally new car object and return an object which its prototype linked to that car object. So if I create 1000 car objects, I will have 1000 car prototypes instead of one prototype with 1000 delegation links. Am I right? If this is true, can anybody explain me how to correct it?

Reza
  • 3,473
  • 4
  • 35
  • 54
  • Breaks in a car are different than brakes. – Fuhrmanator Sep 17 '18 at 01:38
  • Performance on creating objects probably matters if you're creating lots or often. Also, you should create some HTML if you want to get an idea of performance differences, right? Finally, I'm not sure this is a factory pattern, as there's no typing differences. But factory means many things. – Fuhrmanator Sep 17 '18 at 01:49
  • @Fuhrmanator Can you explain why it's not a factory pattern? – Reza Sep 17 '18 at 11:52
  • 1
    Factory usually implies a function that instantiates a subtype of a class using creation logic. Your example just initializes. Of course, in JavaScript functions can be assigned, so perhaps it matters less. See http://coding-geek.com/design-pattern-factory-patterns/ – Fuhrmanator Sep 17 '18 at 12:44

1 Answers1

2

JSPerf is being buggy so I can't really test against yours, but... I'd say this is more readable and more maintainable, while being fast (using ES6 classes):

const Car = (function() {
  const internal = Symbol("internal");

  class Car {
    constructor(color) {
      this.color = color;
    }

    [internal]() {
      console.log("internal");
      // ...
    }

    gas() {
      this[internal]();
      // ...
    }

    break() {
      // ...
    }
  }

  return Car;
})();

let car = new Car("red");
car.gas();
console.log(car);

Since you can access the symbol impersonating a private method using Object.getOwnPropertySymbols, but not accidentally, the symbol way is "good enough" for me (as in, any secrets I have I'm not transmitting to the client, and private methods are purely for programmers' idea of what is public API and what is not. If this is not "good enough" for you, then this is as performant, though you lose internal being a proper method:

const Car = (function() {
  function internal(car) {
    console.log("internal");
  }

  class Car {
    constructor(color) {
      this.color = color;
    }

    gas() {
      internal(this);
      // ...
    }

    break() {
      // ...
    }
  }

  return Car;
})();

let car = new Car("red");
car.gas();
console.log(car);

The outer IIFE is simulating a module (see JavaScript module pattern with example); you don't need it if you are using proper modules.

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • Thanks for your recommended pattern, but lots of experts says that using "class" in JS is a bad practice and you should avoid it cause it's not what you think of class existed in classical inheritance. I prefer to not use this pattern although it's pretty much the same as the constructor pattern. – Reza Sep 17 '18 at 11:49
  • 1
    Avoiding a useful tool because you think you might not be understanding it right is not very expert in my opinion. I’d rather learn my tools properly and use them as they are. There is absolutely nothing wrong with ES6 classes, as long as you know they are not Java classes, and are aware of how they behave; and while they are pretty much just syntax sugar around prototypical inheritance, they are way more readable. But suit yourself. – Amadan Sep 17 '18 at 12:22