Design Patterns Overview.
Creational Patterns.

What are design patterns?

What are design patterns?

History

From the 1977 book on architecture: "A Pattern Language: Towns, Buildings, Construction"

Each pattern describes a problem that occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.

In computer science

The Gang Of Four book:
"Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides

Creational design patterns

Creational design patterns

About

Creational design patterns focus on object creation mechanisms
Summaries best practices for object creation suitable for different, common, situations
Removes the potential complexity in a project
Some of the patterns that fall under this category are: Factory, Abstract, Prototype, Singleton and Builder

Create single object

There are various ways to create an object in JS:

		// by object literal
		const objLiteral = {}

		// by Object.create method
		const objCreateNormal = Object.create({});
		const objCreateNull = Object.create(null);

		// by Object.assign method
		const objAssign = Object.assign({},{});

		// by Object constructor
		const objObjectConstructor = new Object()

		console.dir(objLiteral);
		console.dir(objCreateNormal);
		console.dir(objCreateNull);
		console.dir(objAssign);
		console.dir(objObjectConstructor);

		// OUTPUT
		// {}
		// {}
		// [Object: null prototype] {}
		// {}
		// {}

  		

The Factory Pattern

The Factory Pattern

The Factory Pattern

The Factory Pattern deals with the problem of creating objects (we can think of them as 'products') without the need to specify the exact class of object being created.
I.e. this pattern abstracts the object creation:
It offers great flexibility and implementation independence.

Factory Pattern - example


			"use strict";

			// aux constructors
			function AudioPlayer(name){
			  this.name = name;
			  this.play = ()=>{
			    console.log(`${this.name} is playing on Audio Player!`);
			  }
			}
			function VideoPlayer(name){
			  this.name = name;
			  this.play = ()=>{
			    console.log(`${this.name} is playing on Video Player!`);
			  }
			}

			// the factory
			function mediaPlayerMaker(name) {
			  if(name.match(/\.(?:mp3|ogg|flack)$/i) ){
			    return new AudioPlayer(name);
			  }else if (name.match(/\.(?:mp4|avi|divx)$/i)) {
			    return new VideoPlayer(name);
			  }
			}

			// the instances
			const player1 = mediaPlayerMaker('time_lapse.mp3');
			const player2 = mediaPlayerMaker('micahel_nyman_band_live.avi');

			// the usage
			player1.play();
			player2.play();

			// time_lapse.mp3 is playing on Audio Player!
			// micahel_nyman_band_live.avi is playing on Video Player!
		

The Factory as mechanism to enforce encapsulation

As we saw, the only way to enforce encapsulation in JavaScript is by function scopes and closures
And Factory is just a function!

			const accountFactory = function(balance){
				// private members
				let _balance = balance;

				// public
				const obj = {
					getBalance: ()=>_balance,
					setBalance: (b)=>_balance = b,
				};

				return obj;
			}

			const obj1 = accountFactory(999999999);

			// let's try to change the balance directly:
			obj1._balance = 0;
			console.log(`New Balance: ${obj1.getBalance()}`);
			;
			// Balance = 999999999

			// let's try to change the balance through the setter:
			obj1.setBalance(0);
			console.log(`New Balance: ${obj1.getBalance()}`);
			// Balance = 0
		

The Factory as mechanism to enforce encapsulation - Getter And Setter Example


			const accountFactory = function(balance){
				// private members
				let _balance = balance;

				// public
				const obj = {
					get balance(){
						return _balance
					},
					set balance(b){
						_balance = b
					}
				};

				return obj;
			}

			const obj1 = accountFactory(999999999);

			// let's try to change the balance directly:
			obj1._balance = 0;
			console.log(`New Balance: ${obj1.balance}`);
			;
			// Balance = 999999999

			// let's try to change the balance through the setter:
			obj1.balance = 0;
			console.log(`New Balance: ${obj1.balance}`);
			// Balance = 0
		

The Singleton Pattern

The Singleton Pattern

about

Singleton provides protection against accidentally creating multiple copies of a complex object.
Allows deferral of object instantiation until the first use.
It's main usage is for managing the global application state and name-spacing.
In short, the main idea of the Singleton is to have only one instance of a specific class.
Perhaps the most overused pattern, though it has fallen out of favour in recent years.

usage

for namespacing, i.e. to reduces the number of global variables
used to organize the code in a consistent manner,
Note that from ES6 we can use modules (import/export).

object literal

An object literal can be regarded as the simplest form of Singelton

			var mySingleton={
				property1:"something",
				property2:"something else",

				method1:function(){
					console.log('hello world');
				}
			};
		

caching the singular instance


			function Car(name, speed) {
				// check for existing instance
				if (typeof Car.instance === "object"){
					return Car.instance;
				}

				// set instance properties
				this.name = name || 'Car';
				this.speed = speed || 180;

				// cache the instance
				Car.instance = this;
			}

			// lets try to create 2 instances
			var car1 = new Car('car1', 200);
			var car2 = new Car('car2', 300);

			// test if we have ONLY ONE instance:
			console.log(car1 === car2);
		

Instance in a Closure: rewrite the Constructor


			function Car(name, speed) {
				// cache the instance
				var instance = this;

				// set instance properties
				this.name = name || 'Car';
				this.speed = speed || 180;

				// rewrite the constructor
				Car = function(){
					return instance;
				};
			}

			// lets try to create 2 instances
			var car1 = new Car('car1', 200);
			var car2 = new Car('car2', 300);

			// test if we have ONLY ONE instance:
			console.log(car1 === car2);
		

The Module Pattern

Modules in JavaScript

The Module pattern
AMD modules
CommonJS modules
ECMAScript6 modules

Module Pattern

The Module pattern encapsulates "privacy" state and organization using closures.
Provides a way of wrapping public methods, private methods and variables
Only a public API is returned, keeping everything else within the closure private

Example


			const myModule = (function(){
				// private
				const config = {
					encoding: 'UTF8',
					maxLength: '2048'
				};

				const logDateTime = function () {
					return new Date();
				}


				// API
				const showConfig =  function(){
					for( key in config ){
						console.log(`${key}: ${config[key]}`)
					}
				}
				const changeConfig =  function(key, value){
					config[key] = value;
					console.log(`Configed changed at: ${logDateTime()}`);
				}

				return {
					// from ES6 (Shorthand property names)
					showConfig,
					changeConfig
				}
			})();

			myModule.showConfig();
			myModule.changeConfig("maxLength",1024 );
			myModule.showConfig();
		

ES6 Modules - References

Modules - chapter from Exploring ES6 by Axel Rauschmayer
import @mdn
export @mdn

ES6 Modules - nodejs demo

Using mjs in real-world scenario is not needed/recommended. We config package.json instead.But this is just a simplest demo for module mechanism:

			function foo(){
			  console.log(`foo from moduleA is called!`);
			}

			// exports a constant
			export const PI = 3.14;

			// named exports
			export { foo };
		

			import { foo, PI} from "./moduleA.mjs";

			foo()
			console.log(`PI=${PI}`);
		

			node --experimental-modules main.mjs
		

ES6 Modules - browser demo


			var sqrt = Math.sqrt;

			function square(x) {
						return x * x;
			}
			function diag(x, y) {
						return sqrt(square(x) + square(y));
			}

			export {square, diag}
		

			import {square, diag} from './lib.js'

			console.log(square(11)); // 121
			console.log(diag(4, 3)); // 5
		

note that in browser, we must specify type="module"


			<body>
				<script src="./main.js" type="module"></script>
			</body>
		

These slides are based on

customised version of

Hakimel's reveal.js

framework