O padrão de projeto de fábrica (Factory Method) é um padrão de projeto de software que define uma interface para criar um objeto em uma superclasse, mas permite que as subclasses decidam qual classe de objeto instanciar.
O padrão Método de Fábrica foi criado por Gamma et al. em seu livro "Design Patterns: Elements of Reusable Object-Oriented Software", publicado em 1995. O padrão Método de Fábrica é um dos padrões de criação, que são usados para abstrair a lógica de criação de objetos.
Esse padrão é útil quando você quer que a sua aplicação crie objetos de uma determinada família, mas não se importa com a classe concreta que é instanciada.
Por exemplo, se você estiver criando uma aplicação de gráficos, poderá ter uma superclasse "Gráfico" com uma interface para desenhar o gráfico, e subclasses concretas para gráficos de barras, gráficos de linhas, gráficos de pizza, etc. Você pode usar o padrão de fábrica para criar um gráfico sem se preocupar com a classe concreta que será instanciada.
Neste padrão temos algumas vatangens, que são:
Permite a criação de objetos sem conhecer a sua classe concreta. Isso significa que o código cliente não precisa saber como criar um objeto específico, basta solicitar ao Factory Method que crie o objeto para ele. Isso torna o código mais flexível e fácil de manter, pois permite adicionar novas classes sem precisar alterar o código cliente
Ajuda a separar o código de criação de objetos do código que os utiliza. Isso facilita o gerenciamento do código, pois o Factory Method é responsável por criar os objetos, enquanto o código cliente só precisa saber como usá-los.
Facilita a modificação do sistema, pois permite adicionar novas classes sem precisar alterar o código cliente. Por exemplo, se você precisa adicionar uma nova classe de produto, basta criá-la e adicioná-la ao Factory Method. O código cliente não precisa ser alterado.
Permite a criação de objetos de forma mais eficiente, pois o Factory Method pode implementar lógicas de criação mais sofisticadas, como pool de objetos ou cache de objetos. Isso pode melhorar a performance do sistema.
Outra vantagem do Método de Fábrica é que ele permite adicionar novos tipos de objetos com facilidade, bastando adicionar um novo caso para o tipo de objeto desejado no método de fábrica. Isso é mais fácil do que adicionar novas subclasses para cada novo tipo de objeto.
Segue abaixo um simples exemplo de código usando o padrão Factory method.
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" }
O factoryMethod permite criar objetos de diferentes tipos sem especificar explicitamente a função que será invocada para criar esses objetos.
A função createObject é uma função auxiliar que cria e retorna um objeto com o tipo especificado e um nome. Ela é usada pelo factoryMethod, que aceita um tipo como parâmetro e retorna uma nova função que, quando chamada, cria e retorna um objeto desse tipo.
O factoryMethod pode criar dois tipos de objetos: "car" e "phone". Se um tipo diferente for passado para o método de fábrica, uma exceção será lançada.
As duas últimas linhas de código criam duas funções: createCar e createPhone. Essas funções são criadas passando os respectivos tipos para o abstractMethod. Elas podem ser usadas para criar objetos desse tipo passando um nome para elas. Por exemplo, myCar é um objeto do tipo "car" com o nome "Ford", enquanto myPhone é um objeto do tipo "phone" com o nome "iPhone".
Simples, né ?
Imagine outro cenário na qual a sua gestora de equipe informou que necessita consumir API de CEP e outra de CNPJ para validação de um formulário de cadastro de usuário na sua plataforma.
Os parceiros listados foram:
Segue a solução abaixo:
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' } ], ... }
})
A função createRequest é uma função auxiliar que cria e retorna uma função que faz uma solicitação HTTP à URL especificada, usando o método fetch, e retorna os dados da resposta como um objeto JSON. Ela é usada pelo método de fábrica factoryMethod, que aceita um tipo como parâmetro e retorna uma nova função que, quando chamada, faz uma solicitação à API correta para esse tipo.
O factoryMethod pode criar duas funções diferentes: lookupCep e lookupCnpj. lookupCep é criado passando o tipo "cep" para o factoryMethod, enquanto lookupCnpj é criado passando o tipo "cnpj". Essas funções podem ser usadas para obter os dados de um CEP ou CNPJ, respectivamente, passando o valor do CEP ou CNPJ para elas. As duas últimas linhas de código fazem isso, fazendo solicitações às APIs de CEP e CNPJ e exibindo os resultados no console.
Conclusão.
O padrão Método de Fábrica é um dos padrões de criação, que são usados para abstrair a lógica de criação de objetos. Ele é um dos 23 padrões de projeto conhecidos coletivamente como "Padrões de Projeto GoF" (GoF Patterns).
Que pode ser útil em várias situações, como:
- Quando você tem várias classes relacionadas e precisa escolher qual classe concreta será usada para criar um objeto.
- Quando você tem muitas possíveis classes concretas e precisa escolher qual delas será usada para criar um objeto.
- Quando você quer tornar o código mais flexível e escalável, permitindo adicionar novos tipos de objetos com facilidade.
Espero ter ajudado, até a próxima.
Top comments (0)