Open In App

Factory Method in JavaScript | Design Pattern

Last Updated : 31 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

The Factory Design Pattern is a creational pattern that allows for the creation of objects without exposing the creation logic to the client. It involves creating a separate factory function that is responsible for creating instances of various related objects based on a specified input. In modern software development, the Factory Design Pattern plays a crucial role in creating objects while abstracting away the specifics of their creation. In JavaScript, we can implement this pattern using factory functions.

Example of Factory Method in JavaScript Design Pattern

Below is an example of the Factory Method in JavaScript Design Pattern:

Javascript




// Factory function to create a user based on role and user info
const createUser = (role, userInfo) => {
  // Initialize a user object with common properties
  const user = {
    name: userInfo.name,
    password: userInfo.password
  };
 
  // Define specific additional information based on the role
  const specificInfo = {
    admin: () => ({ role: 'Admin', key: userInfo.key }),
    customer: () => ({ role: 'Customer', address: userInfo.address }),
    seller: () => ({ role: 'Seller', shopAddress: userInfo.shopAddress, contact_No: userInfo.contact_No })
  };
 
  // Get additional information based on the role provided
  const additionalInfo = specificInfo[role] ? specificInfo[role]() : null;
 
  // If an invalid role was specified, throw an error
  if (!additionalInfo) {
    throw new Error('Invalid role specified.');
  }
 
  // Combine the common user properties with additional role-specific properties
  return { ...user, ...additionalInfo };
};
 
// Create an Admin User instance
const adminUser = createUser('admin', {
  name: 'Abhishek',
  password: 'Abhi1233',
  key: '#1244534-fadsv34'
});
 
// Create a Customer User instance
const customerUser = createUser('customer', {
  name: 'John Doe',
  password: 'Password123',
  address: '123 Main St'
});
 
// Create a Seller User instance
const sellerUser = createUser('seller', {
  name: 'Jane Smith',
  password: 'SellerPass',
  shopAddress: '456 Market St',
  contact_No: '123-456-7890'
});
 
// Log the Admin User details
console.log('Admin User:', adminUser);
 
// Log the Customer User details
console.log('Customer User:', customerUser);
 
// Log the Seller User details
console.log('Seller User:', sellerUser);


Output:

Admin User: {

name: ‘Abhishek’
password: ‘Abhi1233’,
role: ‘Admin’,
key: ‘#1244534-fadsv34’

}

Customer User: {

name: ‘John Doe’,
password: ‘Password123’,
role: ‘Customer’,
address: ‘123 Main St’

}

Seller User: {

name: ‘Jane Smith’,
password: ‘SellerPass’,
role: ‘Seller’,
shopAddress: ‘456 Market St’,
contact_No: ‘123-456-7890’

}

Explanation:

const createUser = (role, userInfo) => {

const user = {

name: userInfo.name,
password: userInfo.password

};

Here, we have a function createUser this function is called factory function.
It takes two parameters:

  • Role (representing the user role, e.g., ‘admin’, ‘customer’, ‘seller’)
  • UserInfo (an object containing user-specific information like name, password, etc.).

Inside this function, we start by creating a user object with common properties, name and password, taken from the userInfo object.

const specificInfo = {

admin: () => ({ role: ‘Admin’, key: userInfo.key }),

customer: () => ({ role: ‘Customer’, address: userInfo.address }),

seller: () => ({ role: ‘Seller’, shopAddress: userInfo.shopAddress, contact_No: userInfo.contact_No })

};

Here we define a specificInfo object. It serves as a lookup table where each role (admin, customer, or seller) is associated with a function. These functions return an object with role-specific information based on the provided userInfo.

  • For the ‘admin’ role, the function returns an object with a role of ‘Admin’ and includes a ‘key’ based on the provided userInfo.
  • For the ‘customer’ role, the function returns an object with a role of ‘Customer’ and includes an ‘address’ based on the provided userInfo.
  • For the ‘seller’ role, the function returns an object with a role of ‘Seller’ and includes ‘shopAddress’ and ‘contact_No’ based on the provided userInfo.

This structure allows for role-specific handling of user information, ensuring that each user type (admin, customer, or seller) gets the appropriate properties set based on their role.

const additionalInfo = specificInfo[role] ? specificInfo[role]() : null;

Here, we use the role parameter to retrieve the corresponding function from the specificInfo object. If the role is valid, we call the corresponding function to get the additional role-specific information. If the role is invalid, it returns null.

if (!additionalInfo) {

throw new Error(‘Invalid role specified.’);

}

Here, we check if additionalInfo is null. If it’s null, we throw an error using throw new Error().

return { …user, …additionalInfo };

Finally, if the role is valid, we combine the common user properties (name and password) with the additional role-specific properties using the spread operator

({ …user, …additionalInfo }).

This creates a new object that represents the user with all the appropriate properties based on the specified role, and we return it.

The createUser function essentially acts as a factory, creating a user object based on the provided role and user information.

const adminUser = createUser(‘admin’, {

name: ‘Abhishek’,
password: ‘Abhi1233’,
key: ‘#1244534-fadsv34’

});

const customerUser = createUser(‘customer’, {

name: ‘John Doe’,
password: ‘Password123’,
address: ‘123 Main St’

});

const sellerUser = createUser(‘seller’, {

name: ‘Jane Smith’,
password: ‘SellerPass’,
shopAddress: ‘456 Market St’,
contact_No: ‘123-456-7890’

});

using createUser function to create different type of user according to there role.

console.log(‘Admin User:’, adminUser);

console.log(‘Customer User:’, customerUser);

console.log(‘Seller User:’, sellerUser);

The user information for each type is logged to the console.

Advantages of Factory Method in JavaScript Design Pattern

  • Abstraction and Encapsulation: The factory function encapsulates the logic for creating objects based on role, abstracting away the creation details. Users of the factory don’t need to worry about the intricate creation process.
  • Simplified Object Creation: The factory pattern simplifies object creation. Users only need to call a function, passing the necessary parameters, to get a fully initialized object.
  • Flexibility and Extensibility: The factory can easily accommodate changes and additions of new user roles. Adding a new role is a matter of extending the specific information and adding a function to the specificInfo object.
  • Code Reusability: The creation logic is centralized in the factory function, allowing for reusability across the application. Users can be created consistently wherever needed.
  • Enhanced Readability and Maintainability: The factory pattern improves code readability by abstracting the object creation process. It’s easier to understand the intent of creating a specific type of user by calling a function with a role.
  • Error Handling: The factory can provide structured error handling, ensuring that users adhere to specific roles and fail gracefully with meaningful error messages.

Disadvantages of Factory Method in JavaScript Design Pattern

  • Complexity for Simple Cases: For simple cases where the object creation logic is straightforward, using a factory might introduce unnecessary complexity. Direct object creation might be more appropriate for such scenarios.
  • Potential Performance Overheads: The additional function calls and lookup operations in the factory can introduce a minor performance overhead compared to direct object creation. However, in most cases, this overhead is negligible.
  • Understanding the Factory Logic: For someone unfamiliar with the factory pattern, understanding the role of each function and how the factory creates objects might take some time.
  • Dependency on External Configuration: The factory relies on external configurations (like the specificInfo object) to determine object creation. If these configurations are modified or incorrect, it can lead to unexpected behavior.
  • Potential Overuse: Overuse of the factory pattern can lead to an overly complex codebase, making it harder to understand and maintain. It’s important to use the pattern judiciously and where it provides clear benefits.


Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads