DEV Community

Higor Diego
Higor Diego

Posted on

1

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.

Image of Datadog

How to Diagram Your Cloud Architecture

Cloud architecture diagrams provide critical visibility into the resources in your environment and how they’re connected. In our latest eBook, AWS Solution Architects Jason Mimick and James Wenzel walk through best practices on how to build effective and professional diagrams.

Download the Free eBook

Top comments (0)