DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on

Descomplicando Simple Factory Method

Introdução

O Simple Factory Method não é um padrão de projeto oficial GOF, isso significa que ele não está catalogados nos livros, portanto é reconhecido como uma introdução a outros dois design patterns: Factory Method e Abstract Factory.

Sua função é centralizar a responsabilidade de criar e entregar objetos de acordo com os parâmetros de entrada. Ele ajuda a reduzir o acoplamento e organizar a lógica de criação, por isso é considerado um design pattern criacional.

Quando surge a necessidade?

Como já dito, podemos utilizar quando queremos centralizar a criação de objetos, com o objetivo do cliente não precisar reconhecer as classes concretas, o que gera desacoplamento.

Então, alguns contextos são:

  • Vários tipos de objetos que compartillham a mesma interface
  • Reduzir o acoplamento de criação
  • Facilita manutenção, extensão e escalabilidade do projeto. Se você tem um novo tipo de objeto basta adicionar no Factory sem tocar no cliente.

Exemplo prático

Temos um sistema de geração de boletos que implementam para diferentes bancos:

  • BancoDoBrasil
  • BancoBradesco

Queremos que o cliente da API peça um boleto sem se preocupar com qual classe concreta será instanciada.

Interface do Boleto

public interface IBoleto 
{
        string Gerar();
}

Enter fullscreen mode Exit fullscreen mode

Boletos Concretos

public class BoletoBancoDoBrasil : IBoleto
{
    public string Gerar() => "Boleto gerado pelo Banco A";
}

public class BoletoBradesco : IBoleto
{
    public string Gerar() => "Boleto gerado pelo Banco B";
}
Enter fullscreen mode Exit fullscreen mode

Controller SEM Factory

Nesse exemplo temos os seguintes problemas:

  • Controller acoplado às classes concretas (BancoDoBrasil, BancoBradesco)
  • Adicionar um novo banco mexe diretamente no Controller
  • Código depende diretamente da implementação completa
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class BoletosController : ControllerBase
{
    [HttpGet("{banco}")]
    public IActionResult GerarBoleto(string banco)
    {
        IBoleto boleto;

        switch (banco.ToLower())
        {
            case "BancoDoBrasil":
                boleto = new BoletoBancoDoBrasil();
                break;
            case "BancoBradesco":
                boleto = new BoletoBradesco();
                break;
            default:
                return BadRequest(new { Erro = "Banco não suportado" });
        }

        var resultado = boleto.Gerar();
        return Ok(new { Mensagem = resultado });
    }
}

Enter fullscreen mode Exit fullscreen mode

Controller COM Factory

Aqui, o controller usa a fábrica (Factory), não se importando com as classes concretas:

  • Controller não conhece classes concretas.
  • Fácil de adicionar novos tipos de boletos: só precisa atualizar a factory, o controller continua intacto.
  • Código mais limpo e desacoplado, seguindo o princípio Open/Closed (aberto para extensão, fechado para modificação).

Criando o método estático Factory

public static class BoletoFactory
{
    public static IBoleto Criar(string banco)
    {
        return banco.ToLower() switch
        {
            "BancoDoBrasil" => new BoletoBancoDoBrasil(),
            "BancoBradesco" => new BoletoBradesco(),
            _ => throw new ArgumentException("Banco não suportado")
        };
    }
}
Enter fullscreen mode Exit fullscreen mode
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class BoletosController : ControllerBase
{
    [HttpGet("{banco}")]
    public IActionResult GerarBoleto(string banco)
    {
        try
        {
            var boleto = BoletoFactory.Criar(banco); // Factory faz o trabalho
            var resultado = boleto.Gerar();
            return Ok(new { Mensagem = resultado });
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new { Erro = ex.Message });
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Evolução

Quando o projeto cresce, geralmente o Simple Factory evolui para o Factory Method, onde cada tipo concreto pode ter sua própria classe factory.

Top comments (0)