Padrão Factory em Java: Abstraindo a Criação de Objetos

O Padrão Factory é um dos padrões de design mais empregados no desenvolvimento Java, concebido para desacoplar o processo de criação de objetos da sua utilização. Ele oferece uma abordagem flexível para instanciar classes, permitindo que a lógica de criação seja centralizada em uma entidade específica, conhecida como fábrica, em vez de espalhada por todo o código cliente.

Ao externalizar a responsabilidade de criar objetos para uma classe fábrica, o sistema ganha em manutenibilidade e extensibilidade. O código cliente interage apenas com a fábrica, solicitando um objeto por meio de um tipo genérico ou interface, sem precisar conhecer os detalhes específicos da sua implementação ou o processo exato de instanciamento.

Variantes do Padrão Factory

Existem três formas principais de implementar o Padrão Factory, cada uma com suas particularidades e casos de uso:

  1. Simple Factory (Fábrica Simples): Embora não seja um padrão de design formalmente reconhecido pelo GoF, a Fábrica Simples é um ponto de partida fundamental. Ela utiliza uma única classe para gerar diferentes tipos de objetos com base em um parâmetro fornecido, simplificando a decisão de qual objeto instanciar.
  2. Factory Method (Método Fábrica): Este padrão define uma interface para a criação de objetos, mas delega a decisão sobre qual classe concreta instanciar para as subclasses. O processo de criação é, assim, postergado para as implementações específicas da fábrica.
  3. Abstract Factory (Fábrica Abstrata): A Fábrica Abstrata fornece uma interface para a criação de famílias de objetos relacionados ou interdependentes, sem especificar suas classes concretas. É útil quando o sistema precisa ser independente de como seus produtos são criados, compostos e representados.

Propósito e Aplicação

O objetivo primordial do Padrão Factory é fornecer uma interface para a criação de objetos, permitindo que as subclasses determinem qual classe concrtea instanciar. Isso posterga a decisão de criação de objetos para as subclasses, resolvendo o problema de qual implementação de interface escolher dinamicamente.

Quando Utilizar

Este padrão é particularmente útil em cenários onde:

  • É necessário criar diferentes instâncias de objetos sob diversas condições.
  • Uma classe não pode antecipar o tipo de objetos que precisa criar.
  • Uma classe quer que suas subclasses especifiquem os objetos que ela cria.

Benefícios

  • O cliente da fábrica precisa apenas conhecer o nome ou tipo do objeto desejado, sem se preocupar com a sua classe concreta.
  • Alta extensibilidade: Adicionar um novo tipo de produto geralmente requer apenas a criação de uma nova classe de produto e, dependendo da variante do padrão, uma pequena alteração na fábrica ou a adição de uma nova fábrica.
  • A implementação específica dos produtos é encapsulada, expondo apenas uma interface comum aos clientes.

Considerações

Apesar de suas vantagens, o Padrão Factory pode introduzir complexidade adicional, especialmente o Método Fábrica, onde a adição de um novo produto pode implicar a criação de uma nova classe concreta de produto e, correspondentemente, uma nova classe concreta de fábrica. Isso pode levar a um aumento no número de classes no sistema.

É importante avaliar se a complexidade do padrão é justificada. Para objetos simples, cuja criação é direta (via operador new), o uso de uma fábrica pode ser um excesso.

Estrutura Componentes

O Padrão Factory (em suas formas mais elaboradas como Factory Method e Abstract Factory) é geralmente composto pelos seguintes elementos:

  • Produto Abstrato (Abstract Product): Uma interface ou classe abstrata que declara a interface comum para todos os objetos que a fábrica pode criar.
  • Produto Concreto (Concrete Product): Implementações específicas do Produto Abstrato, representando os objetos reais a serem criados.
  • Fábrica Abstrata (Abstract Factory): Uma interface ou classe abstrata que declara o método(s) para criar os objetos do Produto Abstrato.
  • Fábrica Concreta (Concrete Factory): Uma implementação da Fábrica Abstrata, responsável por instanciar os Produtos Concretos específicos.

Exemplo de Implementação em Java

Para ilustrar, criaremos um sistema para gerenciar diferentes formas geométricas. A ideia é que o cliente solicite uma forma por seu tipo e receba uma instância sem se preocupar com a lógica de criação.

1. Definindo a Interface do Produto Abstrato

Primeiro, definimos uma interface comum para todas as formas geométricas, que especifica a operação principal que elas devem realizar.


// FormaGeometrica.java
public interface FormaGeometrica {
    void desenhar();
}

2. Implementando os Produtos Concretos

Em seguida, criamos as classes concretas que implementam a interface FormaGeometrica, cada uma com sua própria representação do método desenhar().


// Retangulo.java
public class Retangulo implements FormaGeometrica {
    @Override
    public void desenhar() {
        System.out.println("Desenhando um Retângulo.");
    }
}


// Quadrado.java
public class Quadrado implements FormaGeometrica {
    @Override
    public void desenhar() {
        System.out.println("Desenhando um Quadrado.");
    }
}


// Circulo.java
public class Circulo implements FormaGeometrica {
    @Override
    public void desenhar() {
        System.out.println("Desenhando um Círculo.");
    }
}

3. Criando um Enum para os Tipos de Forma

Para tornar a fábrica mais robusta e evitar erros de digitação de strings, podemos usar um enum para representar os tipos de formas.


// TipoForma.java
public enum TipoForma {
    CIRCULO,
    RETANGULO,
    QUADRADO;
}

4. Desenvolvendo a Fábrica de Formas

Agora, criamos a classe fábrica que será responsável por instanciar a FormaGeometrica apropriada com base no TipoForma fornecido.


// FabricaDeFormas.java
public class FabricaDeFormas {

    public FormaGeometrica criarForma(TipoForma tipo) {
        if (tipo == null) {
            return null;
        }
        switch (tipo) {
            case CIRCULO:
                return new Circulo();
            case RETANGULO:
                return new Retangulo();
            case QUADRADO:
                return new Quadrado();
            default:
                // Em um cenário real, poderia lançar uma exceção ou registrar um erro
                return null;
        }
    }
}

5. Utilizando a Fábrica

Por fim, demonstramos como o código cliente interage com a fábrica para obter as instâncias das formas, sem precisar conhecer os construtores das classes concretas.


// TesteFabrica.java
public class TesteFabrica {

    public static void main(String[] args) {
        FabricaDeFormas fabrica = new FabricaDeFormas();

        // Obtém um objeto Círculo e invoca seu método desenhar
        FormaGeometrica forma1 = fabrica.criarForma(TipoForma.CIRCULO);
        if (forma1 != null) {
            forma1.desenhar();
        }

        // Obtém um objeto Retângulo e invoca seu método desenhar
        FormaGeometrica forma2 = fabrica.criarForma(TipoForma.RETANGULO);
        if (forma2 != null) {
            forma2.desenhar();
        }

        // Obtém um objeto Quadrado e invoca seu método desenhar
        FormaGeometrica forma3 = fabrica.criarForma(TipoForma.QUADRADO);
        if (forma3 != null) {
            forma3.desenhar();
        }
    }
}

6. Saída do Programa

Ao executar o programa TesteFabrica, a saída esperada será:


Desenhando um Círculo.
Desenhando um Retângulo.
Desenhando um Quadrado.

Tags: java PadrõesDeProjeto FactoryPattern OrientacaoAObjetos DesenvolvimentoDeSoftware

Publicado em 6-16 19:41 por Thomas