Design Pattern is a Reusable Solution to Recurring Problem were Popularized in the 90s by the almost Legendary Gang of Four (GoF) Split into Three Things Creational, Structural , Behavioral Patterns
Creational Design Patterns Solved Alot Of Problems Related to The Creation Of Object Split into Multiple Patterns
- Factory
- Builder
- Singleton
- Revealing Constructor (Not Related to GoF Patterns)
Solved Problem
- Decouple the Creation of an Object from Implementation
- also can used to Enforce the Encapsulation by Leveraging Closures
What's Meaning By Decouple Creation here ?
like if i want to Refactor Class and add new Classes Will be Dynamically to add new Type
E.G:
Need to Add a Class Handles the Logic Of The Creation of Gif Image
and another one for JPEG Image and so on
if i want to add new Class for Another Different Images and Code Still Clean?
So The Best way to do That is Abstract Factory Pattern
Abstract Factory Dynamic Class Code Snippet
import { ImageGif } from './imageGif.js';
import { ImageJpeg } from './imageJpeg.js';
import { ImagePng } from './imagePng.js';
function createImage(name) {
if (name.match(/\.jpe?g$/)) {
return new ImageJpeg(name);
} else if (name.match(/\.gif$/)) {
return new ImageGif(name);
} else if (name.match(/\.png$/)) {
return new ImagePng(name);
} else {
throw new Error('Unsupported format');
}
}
const image1 = createImage('photo.jpg');
const image2 = createImage('photo.gif');
const image3 = createImage('photo.png');
Builder is Used to Simplifies the Creation of Complex Object by Providing a Fluent interface allow us to Build Object Step by Step The First Question is What's Complex Object and how this Help me ? The Complex Object here is Reference to Object that The Creation of it Takes alot of things Like Takes alot Of Paramters as Input, have a long steps to Create it
Builder is Common patterns in JS As Superagent Already Uses Builder Pattern Because Request takes too many Paramters to it as an input Superagent Builder Source Code
Builder Code Snippet
Builder Result Object
import { UrlBuilder } from './urlBuilder.js';
const url = new UrlBuilder().setProtocol('https').setAuthentication('user', 'pass').setHostname('example.com').build();
Builder Class Note return this it's Related to Chain of Responsibilites we will talk later about this Pattern
export class UrlBuilder {
setProtocol(protocol) {
this.protocol = protocol;
return this;
}
setAuthentication(username, password) {
this.username = username;
this.password = password;
return this;
}
setHostname(hostname) {
this.hostname = hostname;
return this;
}
setPort(port) {
this.port = port;
return this;
}
setPathname(pathname) {
this.pathname = pathname;
return this;
}
setSearch(search) {
this.search = search;
return this;
}
setHash(hash) {
this.hash = hash;
return this;
}
build() {
return new Url(
this.protocol,
this.username,
this.password,
this.hostname,
this.port,
this.pathname,
this.search,
this.hash
);
}
}
The Purpose of Singleton is to Enforece the Presence of only one instance of class and Centralize it's Access
Use Case:
- Sharing Stateful Information
- Optimize the Resource of Usage
- Synchronize access to Resource In The Wild: Database Connection Already Using This Pattern The Easiest Way to Create Singleton in Nodejs is Just to Cache the Module
Singleton Code Snippet
class Calculator {
constructor(initialVal) {
this.initialVal = initialVal;
}
increase(val) {
this.initialVal += parseInt(val);
}
total() {
return this.initialVal;
}
}
module.exports = new Calculator(0);
Every App is The Result of Aggregation of Several Components and App Grows,
the Way we connect these Components Becomses Win Or Lose Factor
For the Maintainability and Success Of The Project
This Great Quote From Nodejs Design Patterns Book And Most of Code Snippets Also
Let's Say we Have A Service(A) >>>>>>>> Service(B)
We want these Services Talks With Each Other and also Reuse These Services in Different Places
So Every time we will Create new Instance From This Service ?
The First Thing Comes in your Mind is to Make It as Singleton
And that's Also what is i was Thinking about at First
But we still have a Problem here is Related to
1- Mock Our Services
2- Let's Say i will change the whole Object Also
these Two Problem Can Solve by Dependency Injection
Just Inject The Object to Another Objection Constructor
Module System with Singleton can Servce as Great Tool for Organizing and Wiring Component Together
but on the other hand they Might Be Tighter Coupling between Components
So Dependency Injection is the Ideal Solution for Wiring Modules Together, And Solving The Coupling between Modules, and Mock Test Cases
Purpose:
- Solving Thightly Coupled Between Modules
- Mock Services Easily
So Now The Communication Between Services is Become Easy By Using Singleton + Dependency Injection
Dependency Injection Code Snippet
export class Blog {
constructor(db) {
this.db = db;
this.dbRun = promisify(db.run.bind(db));
this.dbAll = promisify(db.all.bind(db));
}
initialize() {}
createPost(id, title, content, createdAt) {}
getAllPosts() {}
}
import { Blog } from './blog.js';
const db = createDb(join(__dirname, 'data.sqlite'));
const blog = new Blog(db);
Most of Frameworks already Using these Staff like Nestjs, Laravel,... by Another Pattern Called Inversion of Control (IOC) Allows us to Shift the Responsibilites of Wiring modules to Third Party Package Called (IOC Containers) One of the Most Interseting Typescript IOC Container is InversifyJS
Structural Design Patterns Are Focused on Prodividing ways To Realize Relationshop between Entites
- Proxy: A Pattern That Allows us to Control Access to Another Object
- Decorator: A Common Pattern to Enhance and Add New Functionality to Existing Object
- Adapter: Allows us to Access the Functionality Of Object Using Different Interface like a Wrapper
Proxy Pattern Mainly Control Access to Another Object Called Subject The Proxy and Subject Have Identical The Same Interface (E.G Function names)
- Data Validation: The Proxy Validates the INput Before Forwarding it to the Subject
- Security: Proxy Verifies that the Client is Authorized to Perform the functionality
- Caching: The Proxy Keeps internal Cache so that the Proxied Operation are executed
- Logging: Before Execute the Subject Functionality we can Easily log anything
If You Want Fully Code check Proxy Folder inside StructuralPatterns
- LoopBack: Framework Using Proxy to intercept and enhance method calls on Controllers & Custom Validation
- Vuejs Version3: Has reimplemented Observable properties using Proxy Pattern
Proxy Code Snippet
class Calculator {
divide(dividend, divisor) {
const result = dividend / divisor;
return result;
}
}
class SafeCalculator {
constructor(calculator) {
this.calculator = calculator;
}
divide(dividend, divisor) {
if (divisor === 0) {
throw Error('Division by 0');
}
return this.calculator.divide(dividend, divisor);
}
}
const calculator = new Calculator();
const safeCalculator = new SafeCalculator(calculator);
Structural Design Pattern That Consists in Dynamically Augmenting the Behavior of Existing Object
it's Very Similar to Proxy Design Pattern But There is Some Difference
Diff Between Proxy & Decorator
Decotrator: Allows to Enhance the Functionality of Existing Object with new Behavior
Proxy: is Used to Control the Access to A Concrete or Virtual Object
If You Look at this Picture you will see MethodC() has been added Not Like the same we did at Proxy there is not New Functionality their
One of the most Use Case here if you want to Enhance the Functionality of Existing Object so After Google Created LevelUp Database Most of Developers Enhanced it and used it in different Senarios You Can Look at this Repo Awesome-levelUp-Database
If You Want Fully Code check Decorator Folder inside StructuralPatterns
Decorator Code Snippet
class Calculator {
divide(dividend, divisor) {
const result = dividend / divisor;
return result;
}
}
class EnhancedCalculator {
constructor(calculator) {
this.calculator = calculator;
}
add(X, Y) {
return X + Y;
}
divide(dividend, divisor) {
if (divisor === 0) {
throw Error('Division by 0');
}
return this.calculator.divide(dividend, divisor);
}
}
const calculator = new Calculator();
const enhancedCalculator = new EnhancedCalculator(calculator);
The Adapter Patterns allows us to Access the Functionality of an Object Using Different Interface Like a Wrapper Around any Functionality
adapter would be a Device that allows you to Plug a USB Type-A Cable into USB Type-C Port
-
Payment Online Solution: that you're Going to Wrap you Payment Online Like Stripe/Paypal and Easy you Can Change Between Payment Gateways Dependency-Inversion-With-Payment-Gateway-Using-Stripe-Paypal
-
JugglingDB: Multi Database ORM Using Multiple Adapter to Be Compatible with Different Database
We Are Going to Wrap fs-module and makes our Fs-module and Saving the Result in memory instead of File
If You Want Fully Code check Adapter Folder inside StructuralPatterns and also Highly Recomended Check This Repo if you want to know more about Adapter and Dependency Invesion Principle Dependency-Inversion-With-Payment-Gateway-Using-Stripe-Paypal
Adapter Code Snippet
import FsMemoryAdapter from './fs-adapter-memory.js';
import VirtualMemory from './virtualMemory.js';
const db = new VirtualMemory();
const fs = new FsMemoryAdapter(db);
fs.writeFile('file.txt', 'Hello!', () => {
fs.readFile('file.txt', { encoding: 'utf8' }, (err, res) => {
if (err) {
return console.error(err);
}
console.log(res);
});
});
// try to read a missing file
fs.readFile('missing.txt', { encoding: 'utf8' }, (err, res) => {
console.error(err);
});
Mainly Focus at the Behavior of the Component and how Combine Objects and how to Define The Way the Communicates with Each Other
- How Do i Change Part of Algorithm at the Run time
- How Change Behavior of Object Based on State
- How Do i Iterate over Collection Without Knowing the Implementation
- Strategy: Helps Us Change Parts of Components to Adapt it to Specific needs
- State: Allows us to Change Behavior of Component based on State
- Template: Allows us to Reuse the Structure of Component to Define new One
- Iterator: Iterate over collection without knowing implementation
- Command: Handle Information Transfered , stored and Processed
Change Part Of Algorithm at Runtime and Easily change the whole Logic Based on Context
- if you would like change the way you're Calculating the fees at the runtime
- Like if you want to Implement A Feature Loading Data from A Configuration File one is Json and the other is .ini
- Passport Authentication Library already Uses Strategy To Separate the Common Logic during Authentication Process Like Facebook / Twitter and other Social media Authentication
Strategy & Adapter patterns looks similar to Each others but Adapter Doesn't Add any Behavior Just makes it under another interface so the difference that strategy looks Dynamic and Easily Change but adapter is Static without and Behavior
Strategy Code Snippet
class Shipping {
constructor() {
this.company = '';
}
setStrategy(company) {
this.company = company;
}
calculate(packageMoney) {
return this.company.calculate(packageMoney);
}
}
class UPS {
constructor() {
this.calculate = function (packageMoney) {
console.log('Passed Package Money Here');
console.log(packageMoney);
// calculations...
return '$45.95';
};
}
}
class Fedex {
constructor() {
this.calculate = function (packageMoney) {
console.log('Passed Package Money Here');
console.log(packageMoney);
// calculations...
return '$43.20';
};
}
}
// Two Strategy
var ups = new UPS();
var fedex = new Fedex();
// Context we have
var shipping = new Shipping();
shipping.setStrategy(ups);
console.log('UPS Strategy: ' + shipping.calculate(packageMoney));
shipping.setStrategy(fedex);
console.log('Fedex Strategy: ' + shipping.calculate(packageMoney));
State Pattern is Specialization of Strategy Pattern Where the Strategy Changes Depending On The State of The Context Because Normal Strategy Remains unChanged For THe Rest of Lifespan Of Context Object
One of the Best Example you can See at the Reactjs App If Anything Changed already Conflict on the Whole Page Without Refresh
Defines Abstract Class that Implements the Skeleton ( Represent Common Parts )
Has Alot in Common with Strategy
The Intent of This Pattern is To Make it Possible to Define a Family of Classes that Are All Variations of A Family of Component
Strategy and Template is Very Similar but the Difference Between the Two Lies in Structure and Implementation.
Both allow us to Change the Variable Parts of Component While Reusing the Common Pars,
Strategy: allows to Do It Dynamically at the runtime
Template: The Complete Component is Determined the moment the concrete class is defined
Template use Case might be More Suitable where we want to create prepackaged variations of Component
when you want to Create you Own Custom Stream and Extends Readable, Writable,... etc You Must Implements Methods like read(), write(), and so On The Create your Custom Stream
Template Code Snippet
class Shipping {
calculate() {
throw new Error('calculate() must be implemented');
}
}
class UPS extends Shipping {
constructor() {
super();
this.calculate = function (packageMoney) {
console.log('Passed Package Money Here');
console.log(packageMoney);
// calculations...
return '$45.95';
};
}
}
class Fedex extends Shipping {
constructor() {
super();
this.calculate = function (packageMoney) {
console.log('Passed Package Money Here');
console.log(packageMoney);
// calculations...
return '$43.20';
};
}
}
var packageMoney = { from: '76712', to: '10012', weigth: 'lkg' };
var ups = new UPS();
var fedex = new Fedex();
console.log('UPS Strategy: ' + ups.calculate(packageMoney));
console.log('USPS Strategy: ' + fedex.calculate(packageMoney));
Iterator Pattern Defines a Common Interface or Protocol for Iterating The Elements of Container Such As Array or Tree Data Structure iterate Different Depends on the Data Structure
Decouple the Implementation of Traversal Algorithm From The Way We Consume The Result
Iterator Pattern is self have so many Different Ways to Implement It,
Like Iterate over Arrays, Iterate over Async Operation Using Generator or Normal Function and so Many things
Here we will use Something Called Javascript Protocol Comes with ES5 Help Us To implement Iterator Pattern
Easily with Normal Async Operations
- Iterate over Data Paginated By REST API and Want to Get All Data
- Iterate over Requests Received By Http Service
- Iterate over Result of an SQL Query
We Are going To Implement Simple Example Send Request to Multiple URLs And Check if Available Or Not Also Check Directory BehavioralPatterns/Iterator Pattern For More Example Using Generators
Iterator Code Snippet
import superagent from 'superagent';
export class CheckUrls {
constructor(urls) {
this.urls = urls;
}
[Symbol.asyncIterator]() {
const urlsIterator = this.urls[Symbol.iterator]();
return {
async next() {
const iteratorResult = urlsIterator.next();
if (iteratorResult.done) {
return { done: true };
}
const url = iteratorResult.value;
try {
const checkResult = await superagent.head(url).redirects(2);
return {
done: false,
value: `${url} is up, status: ${checkResult.status}`,
};
} catch (err) {
return {
done: false,
value: `${url} is down, error: ${err.message}`,
};
}
},
};
}
}
const checkUrls = new CheckUrls([
'https://nodejsdesignpatterns.com',
'https://example.com',
'https://mustbedownforsurehopefully.com',
]);
for await (const status of checkUrls) {
console.log(status);
}
A Command Pattern can be any Object that Encapsulates all the Information neccessary To Perform an Action at later Time So, instead of invoking a method or a function directly, we create an object representing the intention to perform such an invocation.
Most of Functionality has been used to undo(), delay() , run() Speicific Operations
The Best Example of Command Pattern at the Wild is Redux That Separate the Action From The Execution That updated the Reducers it's also often has Been Using In Functional Programming