JavaScript design patterns are reusable solutions to common problems that arise in software design. They provide a template for solving certain issues and can help developers create more maintainable and scalable code. Here's a comprehensive guide to some commonly used design patterns in JavaScript:
Singleton Pattern:
- Ensures that a class has only one instance and provides a global point of access to it.
- Useful for scenarios where a single instance controls actions, such as logging, or managing a pool of resources.
var Singleton = (function () {
var instance;
function createInstance() {
// Private constructor logic
return {};
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
Module Pattern:
- Encapsulates and organizes code into a single, self-contained unit.
- Uses closures to create private and public methods and variables.
var Module = (function () {
var privateVar = 10;
function privateFunction() {
console.log("Private Function");
}
return {
publicVar: 20,
publicFunction: function () {
console.log("Public Function");
}
};
})();
Factory Pattern:
- Defines an interface for creating objects, but leaves the choice of its type to the subclasses.
- Useful when a class cannot anticipate the class of objects it must create.
function CarFactory() {}
CarFactory.prototype.createCar = function (model) {
switch (model) {
case 'Sedan':
return new Sedan();
case 'SUV':
return new SUV();
default:
return new GenericCar();
}
};
Observer Pattern:
- Defines a one-to-many dependency between objects, so that when one object changes state, all its dependents are notified and updated automatically.
- Commonly used in implementing distributed event handling systems.
function ObserverList() {
this.observers = [];
}
ObserverList.prototype.add = function (obj) {
return this.observers.push(obj);
};
ObserverList.prototype.remove = function (obj) {
this.observers = this.observers.filter(observer => observer !== obj);
};
ObserverList.prototype.notify = function (context) {
this.observers.forEach(observer => observer.update(context));
};
Decorator Pattern:
- Attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
- Useful when you need to extend or enhance the behavior of objects in a flexible and reusable way.
function Coffee() {
this.cost = function () {
return 5;
};
}
function MilkDecorator(coffee) {
this.cost = function () {
return coffee.cost() + 2;
};
}
Command Pattern:
- Encapsulates a request as an object, thereby allowing for parameterization of clients with different requests, queuing of requests, and logging of the parameters.
- Useful in decoupling the sender and receiver of a request.
function Command(command) {
this.execute = function () {
console.log("Executing command: " + command);
};
}
MVVM (Model-View-ViewModel) Pattern:
- Separates an application into three main components: Model (data and business logic), View (UI and presentation), and ViewModel (mediator between Model and View).
- Commonly used in the development of single-page applications.
function Model(data) {
this.data = data;
}
function ViewModel(model, view) {
this.model = model;
this.view = view;
}
Promise Pattern:
- Represents a value that might be available now, or in the future, or never.
- Provides a cleaner way to handle asynchronous operations and avoid callback hell.
function asyncOperation() {
return new Promise(function (resolve, reject) {
// Asynchronous operation
if (/* operation successful */) {
resolve(result);
} else {
reject(error);
}
});
}
Facade Pattern:
- Provides a simplified interface to a set of interfaces in a subsystem, making it easier to use.
- Useful for hiding complex implementations and exposing only what is necessary.
function Facade() {
this.operation = function () {
Subsystem1.operation1();
Subsystem2.operation2();
};
}
Strategy Pattern:
- Defines a family of algorithms, encapsulates each algorithm, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
- Useful when you want to define a family of algorithms, encapsulate each one, and make them interchangeable.
```javascript
function Context(strategy) {
this.strategy = strategy;
this.executeStrategy = function () {
this.strategy();
};
}
```
These patterns provide solutions to common problems in software design and help in creating maintainable, scalable, and modular code. It's important to choose the right pattern based on the specific requirements and constraints of your project. Additionally, JavaScript is a flexible language, and sometimes a combination of patterns may be the most suitable approach.
Top comments (0)