DEV Community

Higor Diego
Higor Diego

Posted on

Padrão - Abstract Factory

Abstract Factory

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()

Enter fullscreen mode Exit fullscreen mode

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);

Enter fullscreen mode Exit fullscreen mode

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)