Singleton design pattern with NodeJS

2 months ago

Singleton is Ensure a class only has one instance, and provide a global point of access to it.

Lets say  we want to create a loger class and use it instead of console.log. Then we want to count how many log that printed.

Loger.js

class Logger {

    constructor() {
        this.logs = [];
    }

    get count() {
        return this.logs.length;
    }

    log(message) {
        const timestamp = new Date().toISOString();
        this.logs.push({ message, timestamp });
        console.log(`${timestamp} - ${message}`);
    }

}

module.exports = Logger;

Shopper.js

var Logger = require('./Logger');

var logger = new Logger();

class Shopper {

    constructor(name, money=0) {
        this.name = name;
        this.money = money;
        logger.log(`New Shopper: ${name} has ${money} in their account.`);
    }

}

module.exports = Shopper;

Store.js

var Logger = require('./Logger');

var logger = new Logger();

class Store {

    constructor(name, inventory=[]) {
        this.name = name;
        this.inventory = inventory;
        logger.log(`New Store: ${name} has ${inventory.length} items in stock.`);
    }

}

module.exports = Store;

Index.js

var Logger = require('./Logger');
var Shopper = require('./Shopper');
var Store = require('./Store');

var logger = new Logger();

logger.log('starting app...');

var alex = new Shopper('alex', 500)
var ski_shop = new Store('Steep and Deep Supplies', [
    {
        item: 'Downhill Skis',
        qty: 5,
        price: 750
    },
    {
        item: 'Knit Hat',
        qty: 20,
        price: 5
    }
])

logger.log('finished config...');

console.log(`${logger.count} logs total`);
logger.logs.map(log => console.log(`   ${log.message}`));

run

2019-04-06T15:31:25.652Z - starting app...
2019-04-06T15:31:25.655Z - New Shopper: alex has 500 in their account.
2019-04-06T15:31:25.655Z - New Store: Steep and Deep Supplies has 2 items in stock.
2019-04-06T15:31:25.655Z - finished config...
2 logs total
   starting app...
   finished config...

The count is wrong because we only count the log that printed in the index.js. 

Now lets impliment singleton to fix this problem

Logger.js

class Logger {

    constructor() {
        this.logs = [];
    }

    get count() {
        return this.logs.length;
    }

    log(message) {
        const timestamp = new Date().toISOString();
        this.logs.push({ message, timestamp });
        console.log(`${timestamp} - ${message}`);
    }

}

class Singleton {

  constructor() {
      if (!Singleton.instance) {
          Singleton.instance = new Logger();
      }
  }

  getInstance() {
      return Singleton.instance;
  }

}

module.exports = Singleton;

shopper.js

var Logger = require('./Logger');

var logger = new Logger().getInstance();

class Shopper {

    constructor(name, money=0) {
        this.name = name;
        this.money = money;
        logger.log(`New Shopper: ${name} has ${money} in their account.`);
    }

}

module.exports = Shopper;

store.js

var Logger = require('./Logger');

var logger = new Logger().getInstance();

class Store {

    constructor(name, inventory=[]) {
        this.name = name;
        this.inventory = inventory;
        logger.log(`New Store: ${name} has ${inventory.length} items in stock.`);
    }

}

module.exports = Store;

index.js

var Logger = require('./Logger');
var Shopper = require('./Shopper');
var Store = require('./Store');

var logger = new Logger().getInstance();

logger.log('starting app...');

var alex = new Shopper('alex', 500)
var ski_shop = new Store('Steep and Deep Supplies', [
    {
        item: 'Downhill Skis',
        qty: 5,
        price: 750
    },
    {
        item: 'Knit Hat',
        qty: 20,
        price: 5
    }
])

logger.log('finished config...');

console.log(`${logger.count} logs total`);
logger.logs.map(log => console.log(`   ${log.message}`));