3 Fundamental Design Patterns to create hassle-free application with Javascript

SATURDAY, APRIL 18, 2020    

For every design pattern, we should always start with the problem statement, and then what design pattern to use that may help solve this problem at hand. In this post, I will be sharing my notes that as i was going through pluralSight’s Design patterns for Javascript. Note that the javascript used will be for ES2015.


“…each pattern represents our current best guess as to what arrangement of the physical[virtual] environment will work to solve the problem presented.” - Christopher Alexander


Common problem with its common solution


Pedestrian traffic, sidewalks
Entry and Exit for a public building, revolving doors.
Designing service layers, Module pattern
Overly complicated object interface, Facade pattern
Visibility into state changes, Observer pattern


what makes a pattern


It solves a problem, it is a proven concept that worked in different application which the solution is not obvious a well. These problems that require design patterns are more complicated problems to be solved, beyond just adding in a semi-colon to solve the problem. It described a relationship on how things interact. It has a significant human component in which coders have to be deliberate to do something to achieve this pattern.

If this type of problem has been solved before, why then do we have to implement it again? Design pattern allows us to build a personal dictionary of a common vocabulary to use, so software engineers know what we are talking about easily.


Type of patterns we will be talking about in this topic


  1. Creational type
  • Constructor pattern
  • Module pattern
  • Factory
  • Singleton (different in javascript, good to understand how this work particularly in javascript)

  1. Structural type. The way the objects are structured
  • Decorator
  • Façade
  • Flyweight

  1. Behavioral (how the objects interacts with one another)
  • Command
  • Mediator
  • Observer

Simple fundamentals of Javascript

Object.defineProperty

Object.defineProperty(obj, "name", {
    value: "my name", # This can be a function as well.
    writeable: false, # Ensure that this is a constant and cannot be overwritten
    enumerable: true, # When we do Object.keys and iterate, will this value should up
    configurable: false # Once you set the value, you are not able to set it to a different value anymore
})

Object.create for inheritance

Inheritance is when you create a new object, whatever variables of that object are now configurable.


Creational Design pattern

Constructor Pattern


Use to Create new object with their own object scope. you use the new keyword and that creates a bran new object. links to an object prototype, and binds ‘this’ to the object scope. Implicitly returns ‘this’ well.


When you call new Object, whatever you set to ‘this’ in the function, it will return the ‘this’ as the return variable. Every new object will bind that object’s ‘this’


Prototype = an encapsulation of properties that an object links to. so every new object that is created, they are not created along with the new instance or copied in, they merely link back to that one same prototype variable.

ClassName.prototype.methodName = function(arguments){

}

Var Task = function(name){
    this.name = name;
    this.completed = false;
}

Becomes:

Class Task {
    constructor(name){
        this.name = name;
        this.completed = false;
    }
}

Task.prototype.complete = function(){
    // ... whatever this function is
    this.completed = true; // This 'this' is referencing the Task's this that was bind to the object.
}

Task.prototype.save = function(){
    function.call(this); //this is referring to the Task Object
}

Using this allows for more efficient way of creating new instances.


Module Pattern


The way to encapsulate methods, to create a toolbox of functions to call. Object Literal. Module pattern create functions to create a service. Wrap the set of functions to abstract out the db method calls from the the application layer.


Module pattern is kinda the same as class static functions, in which the external service setups can be abstracted away from the application layer, and just having the application to call some methods that wrapped the actual call to DB. Just a fancy name to do encapsulation and abstraction of external services.


Factory Pattern


A pattern used to simply object creation. Simplifies Object creation
creating different objects based on need. It has a repository creation. So your controller does not have to worry. It is in the factory where you put in the cache, since factory is concern with object creation in which it can fetch from cache and create these object. With the factory pattern as well, you can also help ensure that application side is only getting consistent code that does not have to worry about the cache layer.


Singleton Pattern


Singleton is used to restrict an object to one instance of that object across the application. Remembers the last time you used it, hands back the same instance when called. Usually have a “getInstance” sort of function. If the instance does not exists, it will simply just create a new instance and return back to the caller. Referring back to BotFactory, getFirstBot will check if this.bots has been created, else it will create a new BotTemplate that gets from cache or completely new from the top, and then return that newly created instance.


Usecase: when do you use singleton? When you want to use the same instance and only need to have one instance of this object throughout the entire application. (application design patterns)


In Node.js, every module that are loaded are cached, so when you were to import the same module again, it will be reusing that cached version. Natively nodejs does cache, and thus can effectively create a singleton object for you. So technically when you export an the created instance of your object, whoever that imports that object instance will be the same one instance.


Structural Design Pattern


These patterns are concerned with how objects are made up and simplifies relationships between objects. The composition of objects, and this is about the relationships between objects. This allows you to either extend the functionality of objects using decorator pattern or to simplify functionalities using facade pattern or flyweight.


Decorator Pattern


Allows you to add functionalities into existing objects without being obstructive. More complete inheritance, wraps an object, and protects existing objects, all allowing extending functionalities.


Don’t want to mess with existing objects by adding in new functions or you can overwrite existing tasks without changing the existing Object.

Task.prototype.save = function (){
    // this is the original save function implementation;
}

urgentTask.save = function (){
    this.notify(); // decorating the existing functions and extending the current functionality
    Task.prototype.save.call(this); // this allows you to call save of the original Object in which this Object was first created, despite it being overwritten.
}

const UrgentTask = function(name, priority){
    Task.call(this, name);
    this.priority = priority
}
const ut = new UrgentTask("name", 1);
console.log(ut) // {name: "name", completed: false, priority: 1}

But Task.call, UrgentTask still does not have access to Task’s functions that are in its prototype. So we have to map that using:


UrgentTask.prototype = Object.create(Task.prototype); // Object.create to ensure that you changing UrgentTask's prototype, it does not change Task's. This is part of the decorator's pattern's principle to follow. Add or extend existing functionalities without changing the existing implementation.

Decorator pattern allows us to know we have ZERO risks of breaking any of the existing object’s functionalities. and Task.prototype.save.call(this); means to allow you to call Task’s save function, reusing the original base object’s function.


Facade Pattern


use a simplified interface to a complicated system. Think about the front of a building, you dont see all the chaos and complexity of the functions that are happening behind the scene. Think of JQuery, they do all the dirty work for you but only giving a clean simple interface for you to use. This difference between facade and decorator pattern is: facade pattern does not create or add or edit existing functionalities, it is only wrapping it up with a cleaner and more simple interface. Maintaining the same functionalities


Flyweight


conserves memory by sharing portions of an object and sharing between objects. There are another of non unique data that could be shared, and when we share, we can save memory. Kinda similar to object.prototype but a different way. But same objective, used only if you are dealing with A LOT of objects, else the saving of memory might be insignificant. You can check out how much of memory is used by this memory

const afterMemory = process.memoryUsage().heapUsed;

You are sharing the data that are, in amalgamation unique, so you can reuse them when the objects are coming back. It is kinda like singleton but for the properties within an object. But this is not the same because this is dealing with properties of an object instead of wanting just one instance throughout the entire application. Their usecases are different, since flyweight is mainly to save memory usage when there are large numbers of objects needed to be created.


Take note and look out for applications of this design pattern, because it will definitely reap a ton of results when the application is scaled.


Behavioral patterns


Concerned with the assignment of responsibilities between objects and how they communicate. Concerned with the responsibilities between object, and helping objects to cooperate, assign clear hierarchy, and encapsulate requests.


Observer Pattern


Allows a collection of objects to watch an object and be notified of changes. This allows for a loosely coupled system, and not actively calling out to different systems, one object is the focal point and the rest of the objects are just looking at that for changes. Subject and Observers, whenever there is a change, subject will notify the observer list of applications.


Creating our subject with the observer lists. That is needed. Creating the observerList, then you create a subject. While the subject is created already, we should use the decorator pattern to extend that subject to allow it to be Observable. A subject usually always have two parameters, 1. the notify(), 2. observerList to notify.


## First part is to allow the Object to have a list of ObserverList, and also the add and count of that observerList array.
var ObservableTask = function (data){
    Task.call(data);
    this.observers = new ObserverList();
}

## second part, to have the notify function that will iterate through the observerList so whatever function we want to be observed, we can just extend using the decorator pattern.
ObservableTask.prototype.notify(task){

}

Mediator Pattern


Controls communication between objects so neither object has to be coupled to the others. This is different from the observer pattern where the subject has to know everyone that wishes to be notified, but mediator pattern, NEITHER sides has to know about one another. One object manages all communication: 1 to many relationship.


Mediator sits between the subject and observer, and decides what to do before pushing out the events to the observers. It has channels, subscribe function, publish function.


const args = Array.prototype.slice.call(arguments, 1); // arguments is basically all the arguments that are passed into a function, so you can do slice, 

const sub = mediator.channels[channel][i];
sub.func.apply(sub.context, args); // apply allows you to pass in an array of args that it is doing now.

Call method requires you to pass in every single parameter one by one.


Command Pattern


Encapsulates the calling of a method as an object. Fully decouples the execution from the implementation. You can use Object.execute(“name of function to execute”, any argument you want); It allows you to save each of the commands that were executed, so you can allow replay of these commands.




I’ve included in a video related to decorator design pattern. I personally find it really useful to understand this fundamental design pattern above all else. Hope you enjoy it