# Design Patterns

# Design Patterns

  • Keep it Simple.

Design patterns in Javascript provide you with repeatable solutions to common problems. These are a few of the design patterns that are important to know.

  • Creational - Creating objects
  • Structural - Relation between objects
  • Behavioral - Communication between objects
  • Concurrency - Multi-threaded programming paradigms (Active object, Nuclear reaction, Scheduler)
Creational Patterns Structural Patterns Behavioral Patterns Architectural
Simple Factory Adapter Chain of Responsibility Module
Factory Method Bridge Command Constructor
Abstract Factory Composite Iterator MVC (Model-View-Controller)
Builder Decorator Mediator MVP (Model-View-Presenter)
Prototype Facade Memento MVVM (Model-View-ViewModel)
Singleton Flyweight Observer
Proxy Visitor
Strategy
State
Template Method

# Architectural Patterns

# Constructor

function Foo(params) {
  this.params = params;
}

let obj = new Foo();

# Module

  • Keep something as private yet accessible.
  • Cons
    • new property/methods added dynamically to obj has no access private variables..
let collection = (function() {
  // private
  let obj = [];

  // public
  return {
      addObj: ....,
      removeObj: ....,
      getObj: ....
  }
})();

collection.addObj({....});

# Creational Patterns

# Singleton

  • Used when we need only one instance of a class.
  • eg: configuration object, session object, etc
let singletonConfig = (function() {
  let config;

  function createConfig(options) {
    // create a obj
  }

  return {
    create: (options) => {
      if (config === undefined) config = new createConfig(options);
      else return "Already configured.";
    },
    get: () => {
      if (config === undefined) return "Not configured.";
      else return config;
    },
  };
})();

# Prototype

let proto = {
  // some functions
};

function Foo(a) {
  let a = a || "somethingdefault";

  function constuctorFunc(x) {
    this.x = x;
  }

  let instance = new constuctorFunc(a);
  return instance;
}

// all instance share the proto functions instead of adding in all instances.
let obj = new Foo("data");
let obj2 = new Foo("data2");

# Structural Patterns

# Facade

  • An abstraction layer. A simple interface use.
jQuery(".parent .child div.span");

# Behavioral Patterns

# Observer (Publisher/Subscriber)

  • 2 parts - Subject and Observers.
  • Publisher/Subscriber is a slight modified version of Observer Pattern. It is more loosely coupled.
  • In Observer - subject has a references to subscribed Observers and calls methods directly
  • In Publisher/Subscriber - A communication channel is used. Publisher just fires event and runs callback sent for that event.
  • Useful in firing multiple callbacks for single event.
let publishSubscribe = {};

(function(container) {
  let countId = 0;

  // Subsribe
  container.subscribe = (event, callback) => {
    // register new event if not present
    if (!(event in container)) container[event] = [];

    // add callback to the list of callbacks
    // All callbacks will be executed when event is fired
    container[event].push({
      "id: ++countId,
      "callback": callback
    });
  };

  // Unsubsribe
  container.unsubscribe = (event, subscriberId) => {
      // just remove subscriberId from container
  };

  // Publish
  container.publish = (event, data) => [
      for(subscriber of container[event]){
          subscriber.callback(data);
      }
  ];
})(publishSubscribe);


// Subscribe to events
let sub1 = publishSubscribe.subscribe('clickedFoo', foo());
let sub2 = publishSubscribe.subscribe('clickedFoo', foo2());
let sub3 = publishSubscribe.subscribe('clickedBar', bar());

// publish
publishSubscribe.publish('clickedFoo', {"data": "someEventData"}); // runs foo(), foo2()
publishSubscribe.publish('clickedBar', {"data": "someEventData"}); // runs bar()

# Command

  • We create an abstraction layer(just like interface) over the actual executing code.
// Execution
let invoker = {
  add: (x, y) => {
    return x + y;
  },
  subtract: (x, y) => {
    return x - y;
  },
  multiply: (x, y) => {
    return x * y;
  },
};

// abstraction (interface) layer
let abstractManager = {
  execute: (name, ...args) => {
    if (name in invoker) {
      return invoker[name].apply(invoker, args);
    }
  },
};

manager.execute("add", 3, 5); // 8
Last Updated: 11/18/2021, 7:23:03 PM