The factory design pattern (Factory Method) is a software design pattern that defines an interface for creating an object in a superclass, but allows subclasses to decide which object class to instantiate.
The Factory Method pattern was created by Gamma et al. in his book "Design Patterns: Elements of Reusable Object-Oriented Software", published in 1995. The Factory Method pattern is one of the creation patterns, which are used to abstract the object creation logic.
This pattern is useful when you want your application to create objects of a certain family, but you don't care which concrete class is instantiated.
For example, if you are creating a charting application, you might have a "Chart" superclass with an interface for drawing the chart, and concrete subclasses for bar charts, line charts, pie charts, and so on. You can use the factory pattern to create a graph without worrying about the concrete class that will be instantiated.
In this pattern we have some advantages, which are:
Allows the creation of objects without knowing their concrete class. This means that the client code doesn't need to know how to create a specific object, it can just ask the Factory Method to create the object for it. This makes the code more flexible and maintainable as it allows you to add new classes without having to change the client code.
Helps to separate the code creating objects from the code that uses them. This makes managing the code easier, as the Factory Method is responsible for creating the objects, while the client code just needs to know how to use them.
Facilitates system modification, as it allows adding new classes without having to change the client code. For example, if you need to add a new Product class, just create it and add it to the Factory Method. The client code does not need to be changed.
Allows you to create objects more efficiently, as the Factory Method can implement more sophisticated creation logics, such as object pooling or object caching. This can improve system performance.
Another advantage of the Factory Method is that it allows you to easily add new object types, just by adding a new case for the desired object type in the factory method. This is easier than adding new subclasses for each new object type.
Below is a simple code example using the Factory method pattern.
function createObject(type) {
return function returnObject(name) {
return { type, name: name}
}
}
function factoryMethod (type) {
switch(type){
case 'car':
return createObject(type)
case 'phone':
return createObject(type)
default:
throw new Error('Unknown type')
}
}
const createCar = factoryMethod("car");
const myCar = createCar("Ford");
console.log(myCar); // { type: "car", name: "Ford" }
const createPhone = factoryMethod("phone");
const myPhone = createPhone("iPhone");
console.log(myPhone); // { type: "phone", name: "iPhone" }
The factoryMethod allows creating objects of different types without explicitly specifying the function that will be invoked to create these objects.
The createObject function is a helper function that creates and returns an object with the specified type and name. It is used by factoryMethod, which accepts a type as a parameter and returns a new function that, when called, creates and returns an object of that type.
The factoryMethod can create two types of objects: "car" and "phone". If a different type is passed to the factory method, an exception will be thrown.
The last two lines of code create two functions: createCar and createPhone. These functions are created by passing their respective types to the abstractMethod. They can be used to create objects of this type by passing a name to them. For example, myCar is an object of type "car" named "Ford", while myPhone is an object of type "phone" named "iPhone".
Simple, right?
Imagine another scenario in which your team manager informed you that you need to consume CEP API and another CNPJ API to validate a user registration form on your platform.
The partners listed were:
Follow the solution below:
const API_URL_CEP = 'https://brasilapi.com.br/api/cep/v1'
const API_URL_CNPJ = 'https://www.receitaws.com.br/v1/cnpj'
function createRequest(url) {
return function(data) {
return fetch(`${url}/${data}`).then(response => response.json())
}
}
function factoryMethod (type) {
switch(type) {
case 'cep':
return createRequest(API_URL_CEP)
case 'cnpj':
return createRequest(API_URL_CNPJ)
default:
throw new Error('Unknown type')
}
}
const lookupCep = factoryMethod('cep')
lookupCep('01001000')
.then(address => {
console.log(address) // { cep: '01001000', state: 'SP', city: 'São Paulo', neighborhood: 'Sé', street: 'Praça da Sé', service: 'correios' }
})
const lookupCnpj = factoryMethod('cnpj')
lookupCnpj('06990590000123')
.then(cnpj => {
console.log(cnpj) // { atividade_principal: [ { code: '63.19-4-00', text: 'Portais, provedores de conteúdo e outros serviços de informação na internet' } ], ... }
})
The createRequest function is a helper function that creates and returns a function that makes an HTTP request to the specified URL using the fetch method and returns the response data as a JSON object. It is used by the factoryMethod factory method, which takes a type as a parameter and returns a new function that, when called, makes a request to the correct API for that type.
The factoryMethod can create two different functions: lookupCep and lookupCnpj. lookupCep is created by passing the type "cep" to the factoryMethod, while lookupCnpj is created by passing the type "cnpj". These functions can be used to get the data of a CEP or CNPJ, respectively, passing the CEP or CNPJ value to them. The last two lines of code do just that, making requests to the CEP and CNPJ APIs and displaying the results in the console.
Conclusion.
The Factory Method pattern is one of the creation patterns, which are used to abstract object creation logic. It is one of 23 design patterns known collectively as "GoF Design Patterns".
Which can be useful in several situations, such as:
- When you have several related classes and need to choose which concrete class will be used to create an object.
- When you have many possible concrete classes and need to choose which one will be used to create an object.
- When you want to make the code more flexible and scalable, allowing you to easily add new types of objects.
Hope this helps, until next time.
Top comments (0)