Design Patterns in JavaScript

Introduction

Design patterns are reusable solutions to a specific problem. Over the many years practicing software development, experts have figured out ways of solving similar problems.

- Anthony Dillon / @anthonydillon

Type of Design Patterns

  • Creational patterns focus on ways to create objects or classes.
  • Structural design patterns focus on ways to manage relationships between objects so that your application is architected in a scalable way
  • Behavioural patterns focus on communication between objects

Data Types in JavaScript

You may hear references to classes and objects in this presentation, but as JavaScript doesn't really have the construct of "class", think of it as a "data type"

JavaScript is an object-orientated language where the inheritance comes from the concept of prototype functions.

Simple Car Data Type


	function Car($config) {
	    this.make = $config.make;
	    this.colour = $config.colour;  
	}  
	  
	Car.prototype.getColour = function() {  
	    return this.colour;  
	};  
	  
	var myCar = new Car({make:"Honda", colour:"Black" });  
	console.log(myCar.getColour()); // outputs Black
					

Since multiple Car objects will reference the same prototype this allows the getColour() method to be shared by all instances of the Car data type

Creational Design Patterns

We are going to focus on two creational design patterns here:

  • Builder pattern
  • Prototype pattern

Builder Pattern

Applying the builder pattern allows us to construct objects by only specifying the type and the content of the object. We don't have to explicitly create the object.

You have probably used the Builder Pattern before without realising it.


						var myDiv = $('<div id="myDiv">This is a div.</div>');
					

Prototype Pattern

The prototype pattern is a pattern where objects are created based on a template of an existing object through cloning.


	var Car = {  
	    make: "Honda",
	    colour: "Black"  
	};  
	    
	var myCar = Object.create(Car);  
	  
	console.log(myCar.colour); //outputs Black 
	myCar.colour = "Blue";  
	console.log(myCar.colour) //outputs Blue
					

Structural Design Patterns

Structural design patterns are really helpful when figuring out how a system should work. They allow our applications to scale easily and remain maintainable.

Lets look at a couple of examples:

  • Composite pattern
  • Facade pattern

Composite Pattern

The composite pattern says that a group of objects can be treated in the same manner as an individual object of the group.


	$('.myList').addClass('selected');  
	$('#myItem').addClass('selected');  
						

Since the composite pattern uses the same API for both, we can often mistake one for the other and end up with unexpected bugs. This is why YUI, offer two seperate methods of getting elements (Y.one() vs Y.all()).

Facade Pattern

The Facade Pattern provides the user with a simple interface, while hiding it's underlying complexity.


	$(document).ready(function() {
	    //all your code goes here...  
	}); 
					

A facade pattern normalizes browser inconsistencies to ensure that you get expected behaviour across all vendors and versions.

Under the ready() hood


ready: (function() {  
    ...  
    //Mozilla, Opera, and Webkit  
    if (document.addEventListener) {  
        document.addEventListener("DOMContentLoaded", idempotent_fn, false);  
        ...  
    }  
    //IE event model  
    else if (document.attachEvent) {  
        // ensure firing before onload; maybe late but safe also for iframes  
        document.attachEvent("onreadystatechange", idempotent_fn);  
        // A fallback to window.onload, that will always work  
        window.attachEvent("onload", idempotent_fn);  
        ...       
    }  
})
					

Behavioural Design Patterns

Behavioural patterns describe different methods of connecting communication between objects. The two methods we will be looking at today are:

  • Observer pattern
  • Mediator pattern

Observer Pattern

In the Observer Pattern, the subject keeps a list of observers, the subject notifies the observers when something interesting happens. A subject can also remove an observer from the list.

  • publish(data)
  • subscribe(observer)
  • unsubscribe(observer)

Observer in the wild


	var o = $( {} );  
	$.subscribe = o.on.bind(o);  
	$.unsubscribe = o.off.bind(o);  
	$.publish = o.trigger.bind(o);  
	
	document.on( 'tweetsReceived', function(tweets) {
	    $.publish('tweetsShow', tweets); 
	}); 
	
	$.subscribe( 'tweetsShow', function() {
	    .. 
	    $.publish('tweetsDisplayed);  
	});  
	  
	$.subscribe('tweetsDisplayed', function() {  
	    ...  
	});  
					

Mediator Pattern

The Mediator Pattern promotes the use of a single shared subject that handles communication with multiple objects. All objects communicate with each other through the mediator.

The benefit of this pattern over the Observer pattern is that a single object is responsible for communication, whereas in the observer pattern, multiple objects could be listening and subscribing to each other.

Lets check out the code


$('#album').on('click', function(e) {  
    e.preventDefault();  
    var albumId = $(this).id();  
    mediator.publish("playAlbum", albumId);  
});  
var playAlbum = function(id) {
    mediator.publish("albumStartedPlaying", {currentSong: "Without You"});  
};  
var logAlbumPlayed = function(id) {  
    //Log the album in the backend  
};  
var updateUserInterface = function(album) {  
    //Update UI to reflect what's being played  
};
mediator.subscribe("playAlbum", playAlbum);  
mediator.subscribe("playAlbum", logAlbumPlayed);  
mediator.subscribe("albumStartedPlaying", updateUserInterface); 
					

In conclusion

The best thing about design patterns is you dont have to tackle common problems as someone has already applied it successfully in the past.

The average number of lines an amateur writes before the code becomes unmanageable is: 1500... ish

THE END

by Ant / anthonydillon.com

Further reading: Learning JavaScript Design Patterns