Design patterns in JavaScript are reusable solutions to common software design problems. They provide guidelines and best practices for structuring and organizing code, improving code quality, maintainability, and reusability. Here are some commonly used design patterns in JavaScript:
1. Module Pattern: Encapsulates related functions and variables into a single module, providing a way to create private and public members. It promotes encapsulation and helps avoid global namespace pollution.
var CounterModule = (function() {
var count = 0;
return {
increment: function() {
count++;
},
getCount: function() {
return count;
}
};
})();
CounterModule.increment();
CounterModule.increment();
CounterModule.getCount(); // Output: 2
CounterModule.count; //Ouput : 'undefined' as it is a private variable
2. Singleton Pattern: Restricts the instantiation of a class to a single
object. It ensures that only one instance of a class is created and provides a global access point to that instance.
var Singleton = (function() {
var instance;
function createInstance() {
var object = new Object("I am the instance");
return object;
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
var instance1 = Singleton.getInstance();
var instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // Output: true
3. Factory Pattern: Provides an interface for creating objects but allows subclasses or derived classes to decide which class to instantiate. It abstracts the process of object creation and provides flexibility in object creation logic.
function ShapeFactory() {}
ShapeFactory.prototype.createShape = function(type) {
switch (type) {
case 'circle':
return new Circle();
case 'rectangle':
return new Rectangle();
case 'triangle':
return new Triangle();
default:
throw new Error('Invalid shape type');
}
};
function Circle() {
this.type = 'circle';
}
function Rectangle() {
this.type = 'rectangle';
}
function Triangle() {
this.type = 'triangle';
}
var factory = new ShapeFactory();
var circle = factory.createShape('circle');
var rectangle = factory.createShape('rectangle');
var triangle = factory.createShape('triangle');
console.log(circle.type); // Output: circle
console.log(rectangle.type); // Output: rectangle
console.log(triangle.type); // Output: triangle
4. Observer Pattern: Establishes a one-to-many relationship between objects, where changes in one object (subject) are automatically reflected in other objects (observers). It enables loose coupling between objects and supports event-driven architectures.
function Subject() {
this.observers = [];
}
Subject.prototype.addObserver = function(observer) {
this.observers.push(observer);
};
Subject.prototype.removeObserver = function(observer) {
var index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
};
Subject.prototype.notifyObservers = function(data) {
this.observers.forEach(function(observer) {
observer.update(data);
});
};
function Observer(name) {
this.name = name;
}
Observer.prototype.update = function(data) {
console.log(this.name + ' received data: ' + data);
};
var subject = new Subject();
var observer1 = new Observer('Observer 1');
var observer2 = new Observer('Observer 2');
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers('Hello'); // Output: Observer 1 received data: Hello
// Observer 2 received data: Hello
These are just a few examples of design patterns in JavaScript. Each pattern has its own purpose and solves specific design problems. It's important to understand their concepts and principles to effectively apply them to different software development scenarios.