Introdução ao padrão de projeto Factory Method no DDD

Quando falamos em Domain-Driven Design (DDD), alguns conceitos são imprescindíveis para a correta compreensão e aplicação desta abordagem. Um desses conceitos é o de Agregados e, dentro deste contexto, o papel do padrão de projeto Factory Method torna-se fundamental. É através dele que conseguimos simplificar a criação de agregados, otimizando o desenvolvimento e a manutenção de nossos sistemas. Mas antes de adentrarmos no Factory Method, vamos entender um pouco mais sobre o que são agregados no DDD.

Entendendo o conceito de agregados no DDD

Os agregados são componentes-chave em um modelo de domínio. Imagine que você tenha várias classes que precisam trabalhar juntas para executar uma tarefa. Nesse caso, a classe que contém as outras e coordena as ações é chamada de agregado.

A importância dos agregados no DDD

Agregados garantem a consistência do modelo de domínio, já que concentram e coordenam as operações entre os objetos que fazem parte do domínio. Uma mudança em um dos objetos do agregado não passa despercebida pelo agregado. Ele assegura que todas as regras de negócio sejam cumpridas antes de qualquer alteração ser confirmada.

A construção de agregados no DDD

A construção de agregados pode ser um processo complexo. Podem haver dependências a serem resolvidas, lógica de negócios a ser implementada e validações a serem feitas. É aí que entra o Factory Method.

O papel do padrão Factory Method na criação de agregados

O padrão Factory Method tem como principal função encapsular a lógica de criação de um objeto, ou neste caso, de um agregado.

Como o Factory Method facilita a criação de agregados

Ao utilizar o Factory Method, você pode separar a lógica de criação dos agregados do resto do código. Isso permite que você tenha classes especializadas para tratar da criação dos agregados, garantindo uma maior coesão e evitando a dispersão do código de criação por todo o sistema.

Benefícios do Factory Method na construção de agregados

Além da coesão e da facilidade de manutenção, a utilização do Factory Method também facilita a aplicação de boas práticas de programação. Por exemplo, a injeção de dependências e a aplicação de testes automatizados se tornam tarefas mais simples quando utilizamos este padrão.

Aplicando o padrão Factory Method em um exemplo prático

Agora que entendemos a teoria, vamos colocá-la em prática. Imagine que temos um sistema de e-commerce e precisamos criar um agregado para tratar do processo de checkout. Neste caso, podemos utilizar o Factory Method para encapsular toda a lógica de criação deste agregado.

Exemplo de implementação em C#

C#
// Produto Abstrato
public abstract class ObjetoAgregado
{
    public abstract void RealizarAcao();
}

// Produtos Concretos
public class ObjetoAgregadoConcretoA : ObjetoAgregado
{
    public override void RealizarAcao()
    {
        Console.WriteLine("Realizando ação para Objeto Agregado A...");
    }
}

public class ObjetoAgregadoConcretoB : ObjetoAgregado
{
    public override void RealizarAcao()
    {
        Console.WriteLine("Realizando ação para Objeto Agregado B...");
    }
}

// Criador (Factory)
public abstract class FabricaObjetoAgregado
{
    public abstract ObjetoAgregado CriarObjetoAgregado();
}

// Criadores Concretos
public class FabricaObjetoAgregadoA : FabricaObjetoAgregado
{
    public override ObjetoAgregado CriarObjetoAgregado()
    {
        return new ObjetoAgregadoConcretoA();
    }
}

public class FabricaObjetoAgregadoB : FabricaObjetoAgregado
{
    public override ObjetoAgregado CriarObjetoAgregado()
    {
        return new ObjetoAgregadoConcretoB();
    }
}

// Cliente
public class Cliente
{
    private FabricaObjetoAgregado _fabrica;

    public Cliente(FabricaObjetoAgregado fabrica)
    {
        _fabrica = fabrica;
    }

    public void RealizarAcaoObjetoAgregado()
    {
        ObjetoAgregado objetoAgregado = _fabrica.CriarObjetoAgregado();
        objetoAgregado.RealizarAcao();
    }
}

// Uso
public class Programa
{
    public static void Main()
    {
        FabricaObjetoAgregado fabricaA = new FabricaObjetoAgregadoA();
        Cliente clienteA = new Cliente(fabricaA);
        clienteA.RealizarAcaoObjetoAgregado();

        FabricaObjetoAgregado fabricaB = new FabricaObjetoAgregadoB();
        Cliente clienteB = new Cliente(fabricaB);
        clienteB.RealizarAcaoObjetoAgregado();
    }
}

// Fonte:ChatGPT

Neste exemplo, temos uma classe abstrata ObjetoAgregado representando o produto abstrato, e duas implementações concretas, ObjetoAgregadoConcretoA e ObjetoAgregadoConcretoB. O criador abstrato, FabricaObjetoAgregado, declara o método de fábrica CriarObjetoAgregado(), que cada criador concreto (FabricaObjetoAgregadoA e FabricaObjetoAgregadoB) sobrescreve para criar o respectivo produto concreto. O cliente (Cliente) recebe uma fábrica concreta como dependência e a utiliza para criar e realizar ações nos objetos agregados.

Por favor, observe que este é um exemplo simplificado para demonstrar o conceito do padrão Factory Method no contexto da criação de agregados. Em um cenário real, haveria lógica e interações mais complexas envolvidas.

Exemplo de implementação em Java

Java
// Produto Abstrato
abstract class ObjetoAgregado {
    public abstract void realizarAcao();
}

// Produtos Concretos
class ObjetoAgregadoConcretoA extends ObjetoAgregado {
    @Override
    public void realizarAcao() {
        System.out.println("Realizando ação para Objeto Agregado A...");
    }
}

class ObjetoAgregadoConcretoB extends ObjetoAgregado {
    @Override
    public void realizarAcao() {
        System.out.println("Realizando ação para Objeto Agregado B...");
    }
}

// Criador (Factory)
abstract class FabricaObjetoAgregado {
    public abstract ObjetoAgregado criarObjetoAgregado();
}

// Criadores Concretos
class FabricaObjetoAgregadoA extends FabricaObjetoAgregado {
    @Override
    public ObjetoAgregado criarObjetoAgregado() {
        return new ObjetoAgregadoConcretoA();
    }
}

class FabricaObjetoAgregadoB extends FabricaObjetoAgregado {
    @Override
    public ObjetoAgregado criarObjetoAgregado() {
        return new ObjetoAgregadoConcretoB();
    }
}

// Cliente
class Cliente {
    private FabricaObjetoAgregado fabrica;

    public Cliente(FabricaObjetoAgregado fabrica) {
        this.fabrica = fabrica;
    }

    public void realizarAcaoObjetoAgregado() {
        ObjetoAgregado objetoAgregado = fabrica.criarObjetoAgregado();
        objetoAgregado.realizarAcao();
    }
}

// Uso
public class Programa {
    public static void main(String[] args) {
        FabricaObjetoAgregado fabricaA = new FabricaObjetoAgregadoA();
        Cliente clienteA = new Cliente(fabricaA);
        clienteA.realizarAcaoObjetoAgregado();

        FabricaObjetoAgregado fabricaB = new FabricaObjetoAgregadoB();
        Cliente clienteB = new Cliente(fabricaB);
        clienteB.realizarAcaoObjetoAgregado();
    }
}

//Fonte: ChatGPT

Neste exemplo, temos uma classe abstrata ObjetoAgregado representando o produto abstrato, e duas implementações concretas, ObjetoAgregadoConcretoA e ObjetoAgregadoConcretoB. O criador abstrato, FabricaObjetoAgregado, declara o método de fábrica criarObjetoAgregado(), que cada criador concreto (FabricaObjetoAgregadoA e FabricaObjetoAgregadoB) sobrescreve para criar o respectivo produto concreto. O cliente (Cliente) recebe uma fábrica concreta como dependência e a utiliza para criar e realizar ações nos objetos agregados.

Novamente, ressalto que este é um exemplo simplificado para demonstrar o conceito do padrão Factory Method no contexto da criação de agregados. Em uma situação real, poderiam existir lógicas e interações mais complexas envolvidas.

Exemplo de implementação em Python

Python
# Produto Abstrato
class ObjetoAgregado:
    def realizar_acao(self):
        pass

# Produtos Concretos
class ObjetoAgregadoConcretoA(ObjetoAgregado):
    def realizar_acao(self):
        print("Realizando ação para Objeto Agregado A...")

class ObjetoAgregadoConcretoB(ObjetoAgregado):
    def realizar_acao(self):
        print("Realizando ação para Objeto Agregado B...")

# Criador (Factory)
class FabricaObjetoAgregado:
    def criar_objeto_agregado(self):
        pass

# Criadores Concretos
class FabricaObjetoAgregadoA(FabricaObjetoAgregado):
    def criar_objeto_agregado(self):
        return ObjetoAgregadoConcretoA()

class FabricaObjetoAgregadoB(FabricaObjetoAgregado):
    def criar_objeto_agregado(self):
        return ObjetoAgregadoConcretoB()

# Cliente
class Cliente:
    def __init__(self, fabrica):
        self.fabrica = fabrica

    def realizar_acao_objeto_agregado(self):
        objeto_agregado = self.fabrica.criar_objeto_agregado()
        objeto_agregado.realizar_acao()

# Uso
if __name__ == "__main__":
    fabrica_a = FabricaObjetoAgregadoA()
    cliente_a = Cliente(fabrica_a)
    cliente_a.realizar_acao_objeto_agregado()

    fabrica_b = FabricaObjetoAgregadoB()
    cliente_b = Cliente(fabrica_b)
    cliente_b.realizar_acao_objeto_agregado()

# Fonte: ChatGPT

Neste exemplo, temos uma classe abstrata ObjetoAgregado representando o produto abstrato, e duas implementações concretas, ObjetoAgregadoConcretoA e ObjetoAgregadoConcretoB. A classe FabricaObjetoAgregado é a classe criadora abstrata que declara o método de fábrica criar_objeto_agregado(), que cada criador concreto (FabricaObjetoAgregadoA e FabricaObjetoAgregadoB) implementa para criar o respectivo produto concreto. O cliente (Cliente) recebe uma fábrica concreta como dependência e a utiliza para criar e realizar ações nos objetos agregados.

Este é apenas um exemplo básico para ilustrar o conceito do padrão Factory Method no contexto da criação de agregados usando Python. Em situações reais, podem existir mais complexidades e interações envolvidas.

Testando a aplicação do padrão Factory Method

Testar a aplicação do padrão Factory Method é tão importante quanto implementá-lo. Quando falamos de testes, estamos garantindo que nosso código funciona como esperado e que futuras modificações não quebrarão funcionalidades já existentes.

Conclusão

Concluindo, a utilização do padrão de projeto Factory Method no contexto do DDD é uma excelente forma de garantir uma maior organização e coesão do código, facilitando a manutenção e evolução do sistema como um todo.

Esse conteúdo é parte do material disponibilizado para os participantes do meu grupo de estudos de DDD do Jeito Certo. Você quer participar desse grupo? Clique aqui e veja como funciona.

Dúvidas Frequentes

O que é um agregado no DDD?
Agregados são componentes-chave em um modelo de domínio, que concentram e coordenam as operações entre os objetos que fazem parte do domínio.

O que é o padrão Factory Method?
O Factory Method é um padrão de projeto que encapsula a lógica de criação de um objeto, ou neste caso, de um agregado.

Como o Factory Method facilita a criação de agregados?
O Factory Method permite separar a lógica de criação dos agregados do resto do código, possibilitando a criação de classes especializadas para este fim.

Quais são os benefícios da aplicação do padrão Factory Method na construção de agregados?
Além da maior coesão e facilidade de manutenção, a utilização do Factory Method também facilita a aplicação de boas práticas de programação, como a injeção de dependências e a aplicação de testes automatizados.

O que é injeção de dependências?
Injeção de dependências é uma técnica que permite aumentar a flexibilidade e a testabilidade do código, fornecendo as dependências necessárias para uma classe ao invés de permitir que a classe crie suas próprias dependências.

Elemar Júnior

Fundador e CEO da EximiaCo atua como tech trusted advisor ajudando empresas e pessoas a gerar mais resultados através da tecnologia.

Sessões de masterclass

Seja avisado de novos conteúdos

Gostou deste conteúdo? Então inscreva-se em nossa newsletter para receber notificações de novas publicações como essa:

Veja outros artigos relacionados

Bounded Contexts e Context Mapping: Desmistificando a Comunicação entre Contextos Delimitados

No universo do Domain-Driven Design (DDD), os Bounded Contexts e o Context Mapping são ferramentas indispensáveis para lidar com sistemas...

Domain-Driven Design e Testes: Estratégias para Garantir a Integridade do Modelo de Domínio

Introdução ao Domain-Driven Design (DDD) e sua Importância Em um mundo onde a tecnologia está em constante evolução, o Domain-Driven...

Sistemas Grandes e Complexos: Como o Domain-driven Design Ajuda a Organizar o Código de Forma Eficiente

No mundo da tecnologia, estamos constantemente lidando com sistemas que são não apenas grandes, mas também incrivelmente complexos. Essa complexidade...

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no curso de Introdução ao padrão de projeto Factory Method no DDD:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no curso de Introdução ao padrão de projeto Factory Method no DDD:

Introdução ao padrão de projeto Factory Method no DDD

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Reputação e Marketing Pessoal:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no curso de Introdução ao padrão de projeto Factory Method no DDD:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de DDD do Jeito Certo:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Padrões de Projeto:

Crie sua conta

Preencha os dados a seguir para iniciar o seu cadastro no Grupo Intensivo de Estudos de Algoritmos e Estruturas de Dados:

× Precisa de ajuda?