O padrão de projeto Abstract Factory foi formalizado e descrito como um dos 23 padrões GoF (Gang of Four) no livro "Design Patterns: Elements of Reusable Object-Oriented Software" escrito por Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides em 1994.
O padrão Abstract Factory é um padrão de projeto de software que permite criar famílias de objetos relacionados ou dependentes sem especificar suas classes concretas. Ele é semelhante ao padrão Factory Method, mas é um nível acima, ou seja, em vez de criar apenas um objeto, o padrão Abstract Factory cria uma série de objetos relacionados.
O Abstract Factory tem uma interface para criar cada tipo de objeto desejado, mas deixa as subclasses decidirem quais classes concretas serão usadas. Isso permite que você altere a família de objetos criados sem afetar as classes que usam esses objetos.
Um exemplo de uso de Abstract Factory seria a criação de temas para um aplicativo, onde existem vários temas diferentes com botões, caixas de diálogo e outros elementos de interface do usuário. Cada tema é uma família de objetos relacionados, e o Abstract Factory permitiria que você crie uma nova família de objetos para um novo tema sem afetar as classes que usam esses objetos.
O Abstract Factory é um pouco mais complexo que o padrão de Factory Method, e é usado em situações em que existem várias famílias de objetos relacionados ou dependentes. Ele é útil para se trabalhar com sistemas complexos que possam ser divididos em sistemas menores e mais fáceis de entender.
Uma das principais vantagens do uso do padrão Abstract Factory incluem:
- Abstração da criação de objetos: Como mencionado anteriormente, o Abstract Factory permite que você crie objetos de diferentes tipos sem precisar saber a classe concreta que será usada para criá-los. Isso permite que você altere a família de objetos criados sem afetar as classes que usam esses objetos.
- Escalabilidade e flexibilidade: O padrão Abstract Factory ajuda a manter o código escalável e flexível. Novas famílias de objetos podem ser adicionadas facilmente, sem afetar o código existente.
- Isolamento de lógica de criação: O Abstract Factory permite que você isole a lógica de criação dos objetos da lógica do sistema, tornando-o mais fácil de modificar e manter.
- Reutilização de código: As classes concretas criadas pelo Abstract Factory podem ser reutilizadas em outros lugares do sistema.
Segue o exemplo abaixo do padrão Abstract Factory para criação de diferentes tipos de conexões com banco de dados em um software com nodejs.
class Connection {
constructor(type) {
this.type = type
}
connect() {
// lógica para conectar
}
query() {
// lógica para fazer consultas
}
close() {
// lógica para fechar a conexão
}
}
class MySQLConnection extends Connection {
constructor() {
super('mysql')
}
}
class MongoDBConnection extends Connection {
constructor() {
super('mongodb')
}
}
class ConnectionFactory {
createConnection(type) {
switch (type) {
case 'mysql':
return new MySQLConnection()
case 'mongodb':
return new MongoDBConnection()
default:
throw new Error('Unknown connection type')
}
}
}
const factory = new ConnectionFactory()
const mysqlConnection = factory.createConnection('mysql')
mysqlConnection.connect()
mysqlConnection.query('SELECT * FROM users')
mysqlConnection.close()
const mongodbConnection = factory.createConnection('mongodb')
mongodbConnection.connect()
mongodbConnection.query({})
mongodbConnection.close()
A classe "Connection" é uma classe abstrata que define a interface para as conexões com banco de dados. Ela possui métodos para conectar, fazer consultas e fechar a conexão.
As classes "MySQLConnection" e "MongoDBConnection" são as classes concretas que estendem a classe "Connection" e implementam a lógica específica para cada tipo de conexão.
Elas também definem o tipo de conexão através da chamada a super no construtor.
A classe "ConnectionFactory" é o Abstract Factory propriamente dito, ela tem o método "createConnection" que é responsável por criar as instâncias de conexão de acordo com o tipo passado.
No final do código, é criada uma instância da classe "ConnectionFactory" e é chamado o método createConnection, passando 'mysql' ou 'mongodb' e assim é criado uma instância específica de conexão para cada tipo. Depois disso, os métodos connect, query e close são chamados para as instâncias criadas.
Simples, né ?
Imagine outro cenário na qual a sua gestora de equipe informou que há uma necessidade de construção de uma dashboard cuja a finalidade é listar os usuários e os seus pedidos por meio de uma API interna.
Para resolver a seguinte problemática segue o exemplo abaixo:
class API {
constructor(baseURL) {
this.baseURL = baseURL;
}
fetch(endpoint) {
return fetch(`${this.baseURL}/${endpoint}`)
.then(response => response.json())
}
}
class UsersAPI extends API {
constructor() {
super('https://my-app.com/api/users');
}
getUsers() {
return this.fetch('users');
}
}
class OrdersAPI extends API {
constructor() {
super('https://my-app.com/api/orders');
}
getOrders() {
return this.fetch('orders');
}
}
class APIFactory {
createAPI(type) {
switch (type) {
case 'users':
return new UsersAPI();
case 'orders':
return new OrdersAPI();
default:
throw new Error('Unknown API type');
}
}
}
const factory = new APIFactory();
const usersAPI = factory.createAPI('users');
usersAPI.getUsers().then(console.log);
const ordersAPI = factory.createAPI('orders');
ordersAPI.getOrders().then(console.log);
A classe API é uma classe abstrata que define a interface para as APIs. Ela possui um construtor que recebe a URL base da API e um método fetch que faz uma requisição GET para a API, passando o endpoint específico.
As classes UsersAPI e OrdersAPI são classes concretas que estendem a classe API e implementam a lógica específica para cada tipo de API. Elas também definem a URL base da API através da chamada ao super() no construtor.
A classe APIFactory é o Abstract Factory propriamente dito, ela tem o método createAPI que é responsável por criar as instâncias de API de acordo com o tipo passado.
No final do código, é criada uma instância da classe APIFactory e é chamado o método createAPI, passando 'users' ou 'orders' e assim é criada uma instância específica de API para cada tipo. Depois disso, o método getUsers() ou getOrders() são chamados para as instâncias criadas, e esses métodos já retornam uma Promise que trata o retorno da API.
Você pode utilizar o padrão Abstract Factory quando:
- Você tem várias famílias de objetos relacionadas ou dependentes, e precisa criar objetos dessas famílias sem especificar suas classes concretas;
- Você quer prover uma maneira simples de criar objetos, mas quer ocultar a lógica de criação da sua aplicação;
- Você quer prover uma maneira de alterar as famílias de objetos criados sem afetar as classes que usam esses objetos;
- Quando existe múltiplas combinações de tipos e estruturas de objetos, e essas combinações precisam ser criadas de forma organizada;
- Se você tem um sistema complexo que pode ser dividido em sistemas menores e mais fáceis de entender e quiser encapsular a lógica da criação desses sistemas menores;
- Se você está trabalhando com sistemas orientados a objetos.
Conclusão
Este padrão ajuda a manter o código escalável e flexível, pois novas famílias de objetos podem ser adicionadas facilmente, sem afetar o código existente. Ele também permite que a lógica de criação dos objetos seja isolada da lógica do sistema, tornando-o mais fácil de modificar e manter.
Espero ter ajudado, até a próxima.
Top comments (0)