Desmistificando o Factory Method
Breno Baudson

Breno Baudson @breno_baudson

About: Dev

Location:
Brasil
Joined:
Apr 8, 2025

Desmistificando o Factory Method

Publish Date: Apr 9
0 0

O Factory Method (ou Método de Fábrica) é um padrão de projeto do tipo criacional que oferece uma solução elegante para a criação de objetos em sistemas complexos.

Imagine que você está desenvolvendo um sistema para uma escola que precisa gerenciar alunos, professores e prestadores de serviço, cada um com atributos e comportamentos distintos. Sem um padrão adequado, a criação desses objetos pode se tornar confusa e enrolada como um prato de miojo frio, especialmente se a lógica de criação estiver espalhada por todo o código. O Factory Method visa resolver esses problemas, definindo uma interface para criar os objetos, promovendo desacoplamento, flexibilidade, facilidade de manutenção e adição de novos tipos de objetos no futuro.

Façamos um comparativo entre uma implementação inicial sem padrão definido e uma com o padrão Factory.

Sem padrão definido

Criei a classe que representa Aluno

public class Aluno {
    String nome;
    String sobrenome;
    Long matricula;
}
Enter fullscreen mode Exit fullscreen mode

Criei uma classe Professor

public class Professor {
    String nome;
    String Sobrenome;
    BigDecimal salario;
}
Enter fullscreen mode Exit fullscreen mode

A classe cliente, ao precisar instanciar Aluno e/ou professor precisa conhecer a implementação de cada uma...

public class ServicoPessoa {

    Aluno aluno = new Aluno("Lucas", "Silva", 123456L);
    Professor professor = new Professor("Maria", "Oliveira", new BigDecimal(5000));

    ///// Restante da implementação
}
Enter fullscreen mode Exit fullscreen mode

Por enquanto é uma implementação padrão e comum, não representa riscos não é mesmo!?
Porém, ainda não criamos a classe para Prestadores de Serviço, que podem se dividir em várias outras como serviço de limpeza, manutenção de equipamentos e etc. A implementação traz repetição de código, acoplamento e riscos para o código.
Imaginemos que, a partir de agora todas as pessoas terão mais um atributo para e-mail. Já temos duas classes para refatorar. Imagine ainda que, teremos mais uma classe de funcionários, que terá os mesmos campos e mais atributos específicos. Olhando por este lado, começamos a encontrar potenciais problemas.

Pois bem, vamos refatorar este esqueleto e implementar o tal falado Factory.

Implementando Factory

Uma boa ideia seria criarmos um contrato com os atributos principais, fazendo com que eles não se repitam...

public abstract class Pessoa {
    String nome;
    String sobrenome;
    String email;

    public Pessoa(String nome, String sobrenome, String email) {
        this.nome = nome;
        this.sobrenome = sobrenome;
        this.email = email;
    }

    public Pessoa() {
        // Construtor padrão (sem argumentos)
    }
Enter fullscreen mode Exit fullscreen mode

A partir daqui, as outras classes extenderem a pessoa, herdarão os atributos comuns e declararão apenas os inerentes a cada uma.

public class Aluno extends Pessoa {
    Long matricula;

    public Aluno(String nome, String sobrenome, String email) {
        super(nome, sobrenome, email); // Chama o construtor da classe Pessoa   
    }

    public Aluno() {
        // Construtor padrão (sem argumentos)
    }
}
Enter fullscreen mode Exit fullscreen mode
public class Professor extends Pessoa {
    BigDecimal salario;

    public Professor(String nome, String sobrenome, String email) {
        super(nome, sobrenome, email); // Chama o construtor de Pessoa        
    }

    public Professor() {
    }
}
Enter fullscreen mode Exit fullscreen mode

Com este primeiro passo já eliminamos a repetição de código e começamos a centralizar a lógica, mas podemos ir além..
Com esta refatoração, o cliente ainda precisa conhecer as classe Aluno e Professor para instancia-las. É agora que implementamos o padrão Factory!

Digamos que o nosso intuito inicial seja apenas criar um objeto de pessoa, para isso, iniciei criando uma interface de um factory central, que vai gerenciar a criação dos objetos.

public interface PessoaFactory {
Pessoa criarPessoa(String tipo, String nome, String sobrenome, String email);
}
Enter fullscreen mode Exit fullscreen mode

Agora crio a implementação desta interface

public class PessoaFactoryManeger implements PessoaFactory {

    @Override
    public Pessoa criarPessoa(String tipo, String nome, String sobrenome, String email) {
        if (tipo.equalsIgnoreCase("aluno")) {
            return new Aluno(nome, sobrenome, email);
        } else if (tipo.equalsIgnoreCase("professor")) {
            return new Professor(nome, sobrenome, email);
        }
        return null;
    }

}
Enter fullscreen mode Exit fullscreen mode

Desta forma, as subclasses não precisam conhecer a implementação de Aluno nem Professor. Basta chamar a factory.

public class ServicoPessoa {
    PessoaFactory factory = new PessoaFactory();

    public void criarPessoas() {        
        Pessoa aluno = factory.criarPessoa("aluno", "João", "Silva", "joao.silva@email.com");
        Pessoa professor = factory.criarPessoa("professor", "Maria", "Souza", "maria.souza@email.com");
        //demais implementações, como inserir a nota do aluno, etc.
    }
}
Enter fullscreen mode Exit fullscreen mode

Este é um exemplo mais simples para entendermos a ideia, porém temos várias possibilidades, como:

  • Criar métodos específicos em PessoaFactory, para criar um Professor, por exemplo. Ele já receberia o valor doa tributo salário. Exemplo:
public interface PessoaFactory {
    Pessoa criarPessoa(String tipo, String nome, String sobrenome, String email);

    Professor criarProfessor(String nome, String sobrenome, String email, BigDecimal salario);  

    Aluno criarAluno(String nome, String sobrenome, String email, Long matricula);
}
Enter fullscreen mode Exit fullscreen mode
  • Criar factory especifica para cada tipo de pessoa e delegar as responsabilidades para cada uma. Desta forma, a responsabilidade da PessoaFactoryManeger será apenas decidir qual outra factory chamar. Exemplo:
public class AlunoFactory implements PessoaFactory {
@Override
public Pessoa criarPessoa(String nome, String sobrenome, String email, Long matricula) {
    return new Aluno(nome, sobrenome, email, matricula);
}
}
Enter fullscreen mode Exit fullscreen mode

Estas são possibilidades que, apesar de serem mais trabalhosas na implementação inicial, diminuem muito a complexidade de manutenção, promovem desacoplamento, facilitam implementações de novas implementações de pessoas, proporcionam simplicidade em inserir novos atributos e comportamentos nas classes principais.

Vantagens do Factory Method:

Desacoplamento: desacoplou o código do cliente (que usa os objetos) das classes concretas que implementam esses objetos. O cliente interage apenas com a interface, sem precisar conhecer os detalhes de implementação das classes concretas. Isso deixa o código flexível e fácil de manter.

Flexibilidade: permitiu adicionar novas pessoas sem alterar o código "base". Desta forma fica muito mais fácil adaptar novas necessidades.

Encapsulamento: a utilização do padrão centralizou a lógica de criação dos objetos na fábrica. Facilitou a manutenção e evitou duplicação de código.

Responsabilidade única: cada fabrica foi se tornou responsável por criar um tipo especifico de objeto. Esse comportamento segue o principio de responsabilidade única, deixando o código mais modular e fácil de testar.

Extração de complexidade: caso haja complexidade na criação dos objetos, o cliente não precisa ter este conhecimento.

Desvantagens

Aumento da complexidade inicial: pode aumentar a complexidade inicial do código, principalmente se você tem muitos tipos de objetos para criar.

Procriação das classes: as classes podem se procriar como coelhos, principalmente se usarmos uma factory para cara objeto. Isso pode tornar o código mais difícil de navegar e entender.

Overkill / Exagero: em sistemas simples, o padrão Factory pode ser um exagero e aumentar complexidade ao invés de diminuir. Exemplo: se você tem apenas um ou poucos objetos, e não tem previsão de adicionar novos tipos no futuro.

Custo: embora o Factory facilite a manutenção a longo prazo, ele pode aumentar o custo inicial de manutenção, já que a criação das interfaces e classes de fábrica exigem tempo e esforço.

Considerações finais

Os padrões são poderosos e podem trazer muitos benefícios para os sistemas. No entanto, é importante avaliar as vantagens e desvantagens antes de usa-los. Em sistemas simples, o Factory Method pode ser um exagero, porém, em sistemas complexos ele pode ser um aliado valioso.

Entenda também

Comments 0 total

    Add comment