image

Bootcamps ilimitados + curso de inglês para sempre

80
%OFF
Article image
Paulo Ferreira
Paulo Ferreira10/07/2025 19:42
Share
Microsoft - Azure AZ-900Recommended for youMicrosoft - Azure AZ-900

O padrão de projeto Abstract Factory e eficiência em Python e Java: qual a melhor linguagem?

  • #Java
  • #Python

Introdução

Você já ouviu falar na “Gang of Four”? A expressão é utilizada para se referir aos quatro autores do livro Design patterns – elements of reusable object-oriented software ou “Padrões de projeto - soluções reutilizáveis de software orientado a objetos”. Ele foi publicado em 1995 por Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides. 

Eles definem os padrões de projeto como “descrições de objetos e classes comunicantes que precisam ser personalizadas para resolver um problema geral de projeto num contexto particular”. Em outras palavras, são guias que oferecem alternativas de implementações focadas em dinamicidade, flexibilidade e eficiência. 

Imagine, por exemplo, um aplicativo de navegação GPS. Há incontáveis maneiras de chegar a um destino, mas uma rota pode fazer com que você chegue mais rápido, outra gastando menos combustível e outra evitando os semáforos. A ideia é a mesma, só que para engenharia de software.

Um programa pode utilizar dois, três ou até todos os padrões, a depender de sua complexidade e tamanho. Inicialmente concebidos para funcionar diretamente em relação ao paradigma orientado a objetos (como na linguagem Java), com o tempo a ferramenta também se mostrou poderosa para arquiteturas dinâmicas, como o Python.

Eles são divididos em três categorias: criacionais, comportamentais e estruturais. Aqui, vamos focar apenas em um padrão criacional. Mas espero que a leitura ajude você a querer aprender mais sobre essas soluções, que podem fazer toda a diferença no seu código.

Abstract Factory

Esse padrão tem o objetivo de criar famílias de objetos relacionados ou dependentes sem a necessidade de especificar suas classes concretas. Ela fornece uma interface para criar objetos que são da mesma família para que sejam compatíveis entre si.

Especialmente útil quando:

  • o sistema deve ser independente de como os produtos são criados ou representados;
  • o sistema deve ser montado com um produto de uma família de múltiplos produtos;
  • existe a necessidade de uma biblioteca de classes e produtos que revele somente as interfaces, não suas implementações.

Componentes:

  • AbstractFactory: interface para operações de criação dos produtos abstratos, declarando os métodos necessários;
  • ConcreteFactory: implementa a AbstractFactory, criando uma família específica de produtos;
  • AbstractProduct: interface para um tipo de objeto de produto;
  • ConcreteProduct: implementa a AbstractProduct definindo um objeto de produto a ser criado pela fábrica concreta correspondente.

Exemplo de uso em Python:

from abc import ABC, abstractmethod

# interface para os produtos:
class Camisa(ABC):
  @abstractmethod
  def vestir(self):
      pass

class Sapato(ABC):
  @abstractmethod
  def calcar(self):
      pass


# classe para os produtos concretos masculinos:
class CamisaMasculina(Camisa):
  def vestir(self):
      print("Vestindo camisa masculina.")

class SapatoMasculino(Sapato):
  def calcar(self):
      print("Calçando sapato masculino.")


# classe para os produtos concretos femininos:
class CamisaFeminina(Camisa):
  def vestir(self):
      print("Vestindo camisa feminina.")

class SapatoFeminino(Sapato):
  def calcar(self):
      print("Calçando sapato feminino.")


# interface para fabrica abstrata:
class FabricaModa(ABC):
  @abstractmethod
  def produzir_camisa(self) -> Camisa:
      pass

  @abstractmethod
  def produzir_sapato(self) -> Sapato:
      pass


# classe concreta para as fábricas:
class FabricaMasculina(FabricaModa):
  def produzir_camisa(self) -> Camisa:
      return CamisaMasculina()
  
  def produzir_sapato(self) -> Sapato:
      return SapatoMasculino()
  
class FabricaFeminina(FabricaModa):
  def produzir_camisa(self) -> Camisa:
      return CamisaFeminina()
  
  def produzir_sapato(self) -> Sapato:
      return SapatoFeminino()
  

# Cliente:
def vestir_e_calcar(fabrica: FabricaModa):
  camisa = fabrica.produzir_camisa()
  sapato = fabrica.produzir_sapato()
  
  camisa.vestir()
  sapato.calcar()


# Exemplo de uso:
if __name__ == "__main__":
  print("Moda Masculina:")
  fabrica_masculina = FabricaMasculina()
  vestir_e_calcar(fabrica_masculina)
  
  print("\nModa Feminina:")
  fabrica_feminina = FabricaFeminina()
  vestir_e_calcar(fabrica_feminina)

Implementação em Java:

Implementação das interfaces relativas aos produtos abstratos, no nosso caso, os tipos de roupas:

Camisa.java

package roupas;

public interface Camisa {
  void vestir();
}

Sapato.java

package roupas;

public interface Sapato {
  void calcar();
}

Agora as classes irão herdar das interfaces criadas anteriormente com os métodos definidos:

CamisaFeminina.java

package roupas.feminino;
import roupas.Camisa;

public class CamisaFeminina implements Camisa {
  @Override
  public void vestir() {
      System.out.println("Vestindo a camisa feminina.");
  }
}

SapatoFeminino.java

package roupas.feminino;
import roupas.Sapato;

public class SapatoFeminino implements Sapato {
  @Override
  public void calcar() {
      System.out.println("Calçando sapato feminino.");
  }
}

CamisaMasculina.java

package roupas.masculino;
import roupas.Camisa;

public class CamisaMasculina implements Camisa {
  @Override
  public void vestir() {
      System.out.println("Vestindo uma camisa masculina");
  }
}

SapatoMasculino.java

package roupas.masculino;
import roupas.Sapato;

public class SapatoMasculino implements Sapato {
  @Override
  public void calcar() {
      System.out.println("Calçando sapato masculino.");
  }
}

Agora precisamos da interface para criação de métodos relativos à família de roupas.

FabricaModa.java

package fabricas;
import roupas.Camisa;
import roupas.Sapato;

public interface FabricaModa {
  Camisa criarCamisa();
  Sapato criarSapato();
}

Finalmente, temos as fábricas concretas, que irão criar as roupas concretas:

FabricaFeminina.java

package fabricas;
import roupas.*;
import roupas.feminino.CamisaFeminina;
import roupas.feminino.SapatoFeminino;

public class FabricaFeminina implements FabricaModa {
  @Override
  public Camisa criarCamisa() {
      return new CamisaFeminina();
  }

  @Override
  public Sapato criarSapato() {
      return new SapatoFeminino();
  }
}

FabricaMasculina.java

package fabricas;
import roupas.*;
import roupas.masculino.CamisaMasculina;
import roupas.masculino.SapatoMasculino;

public class FabricaMasculina implements FabricaModa {
  @Override
  public Camisa criarCamisa() {
      return new CamisaMasculina();
  }

  @Override
  public Sapato criarSapato() {
      return new SapatoMasculino();
  }
}

Na classe Main, vamos ter um método para receber uma fábrica específica e criar as roupas de cada sexo e o método main, para criar de fato as roupas e calçados masculinos e femininos:

import roupas.*;
import fabricas.*;

public class Main {
  public static void novoLook(FabricaModa fabrica){
      Camisa camisa = fabrica.criarCamisa();
      Sapato sapato = fabrica.criarSapato();

      System.out.println("Novo look concluído.");
      camisa.vestir();
      sapato.calcar();
  }

  public static void main(String[] args) {
      System.out.println("Novo look masculino sendo montado agora...");
      novoLook(new FabricaMasculina());
      System.out.println("\n");

      System.out.println("Novo look feminino sendo montado agora...");
      novoLook(new FabricaFeminina());
  }
}

Tente replicar os códigos na sua IDE para ver os resultados!

Veredito

Com uma implementação segura, o Java oferece estabilidade e clareza, apesar da necessidade já conhecida de escrever mais linhas de código. Essa robustez pode ser essencial em projetos grandes, que envolvam a participação de equipes em diferentes níveis de complexidade. 

A linguagem pode ser mais verbosa, mas o contrato é claro. Ao utilizar as interfaces de fábrica, o cliente sabe exatamente qual tipo de roupa ou sapato o método deve retornar. Além disso, a utilização dos pacotes junto com o compilador ajuda o desenvolvedor a tratar erros de forma rápida.

Já o Python dispõe de velocidade e flexibilidade. A característica dinâmica intrínseca da linguagem permite fazer alterações de forma ágil. Isso significa que a prototipagem aqui também sai ganhando por conta da alta adaptabilidade. No entanto, a baixa segurança de tipos pode fazer com que um erro seja descoberto somente quando o código for executado. 

Aqui temos claramente um empate: se o seu trabalho envolver prioritariamente programas estáveis, detecção precoce de erros e previsibilidade, vá de Java. Se quer concisão, segurança em protótipos e flexibilidade, corra para o Python.

Share
Recommended for you
Suzano - Python Developer #2
Riachuelo - Primeiros Passos com Java
GFT Start #7 - Java
Comments (3)
Paulo Ferreira
Paulo Ferreira - 16/07/2025 16:36

É uma reflexão e tanto! Sou suspeito pra falar porque gosto muito das duas linguagens, que também estão intrinsecamente relacionadas ao mundo dos dados, por exemplo. Mas vejo sim que seria possível combinar as duas linguagens em um projeto. Acredito que o nível de complexidade deveria ser bastante planejado, mas apesar dos desafios que essa abordagem traria, seria bem interessante explorar um caminho onde as duas seriam utilizadas em conjunto.

DIO Community
DIO Community - 15/07/2025 13:44

Paulo, você fez uma excelente comparação entre Python e Java ao explicar o padrão de projeto Abstract Factory. A maneira como você descreve a aplicação desse padrão tanto em Python quanto em Java ajuda a entender não só as diferenças de sintaxe, mas também as forças de cada linguagem em termos de robustez e flexibilidade.

A implementação em Python, com sua sintaxe mais enxuta e dinâmica, certamente permite uma prototipagem mais rápida, enquanto o Java, com sua tipagem estática e forte suporte a ferramentas corporativas, garante mais segurança e controle para aplicações mais complexas e escaláveis.

Em um cenário onde tanto a prototipagem rápida quanto a robustez em produção são necessárias, você vê um caminho viável para combinar ambos os mundos, talvez com integração entre as duas linguagens, ou ainda existem desafios significativos a serem superados nessa abordagem?

AF

Antônio Félix - 10/07/2025 20:48

Se garantiu mano!

#uniforads

Recommended for youMicrosoft - Azure AZ-900