Design Patterns: o guia definitivo dos Padrões de Projeto | Alura

+2 meses grátis para
acelerar a sua carreira

Tá acabando!

00

DIAS

00

HORAS

00

MIN

00

SEG

Design Patterns: o guia definitivo dos Padrões de Projeto

Um programador afro-brasileiro, usando óculos e fones de ouvido, está sentado em sua mesa, concentrado em seu trabalho. Ele está em frente a três monitores: um laptop aberto e dois monitores maiores, que exibem códigos de programação em uma tela escura. A luz suave do escritório reflete em seus óculos..
Igor Chagas
Igor Chagas

Compartilhe

No universo do desenvolvimento de software, a aplicação de design patterns é a chave para resolver desafios constantes.

Você certamente vai se deparar com questões como:

  • Como criar objetos de forma flexível? 
  • Como fazer com que sistemas complexos se comuniquem de maneira eficiente? 
  • Como garantir que nosso código seja fácil de manter e estender no futuro?

Bom, assim como na engenharia civil não se reinventa a planta de uma viga de sustentação para cada nova construção, na engenharia de software também não precisamos reinventar a roda para cada problema comum que encontramos. 

Pessoas programadoras muito experientes, ao longo de décadas, identificaram problemas recorrentes e desenvolveram soluções elegantes e testadas para eles.

Essas soluções são justamente o que chamamos de Design Patterns, ou Padrões de Projeto. 

Eles são como um manual de boas práticas, um catálogo de soluções consagradas para os dilemas mais comuns na arquitetura de software.

Se você está buscando elevar a qualidade do seu código, escrever software de forma mais profissional e entender como pessoas desenvolvedoras experientes pensam, este guia completo é o seu ponto de partida. 

Vamos mergulhar fundo no que são os Design Patterns, por que são tão importantes e explorar exemplos práticos que você poderá aplicar em seus projetos.

O que são padrões e procedimentos de projetos?

Um Design Pattern não é um pedaço de código que você pode copiar e colar. Não é uma biblioteca ou um framework. 

Um Padrão de Projeto é uma descrição ou um modelo de como resolver um problema específico, que pode ser usado em muitas situações diferentes.

Pense nele como uma receita de culinária. A receita descreve os ingredientes, os passos e o resultado esperado, mas não é a comida em si. 

Você pega a receita, adapta os ingredientes que tem à disposição e segue os passos para criar seu próprio prato. 

Da mesma forma, um Design Pattern oferece a estratégia e a estrutura da solução, e você, como pessoa desenvolvedora, implementa essa estratégia usando a linguagem de programação de sua preferência.

O objetivo principal é fornecer um vocabulário comum para a equipe de desenvolvimento e acelerar o processo, evitando que se perca tempo com problemas já solucionados.

Banner da Alura apresentando o Mochileiro Tech, material gratuito desenvolvido com recrutadores do mercado. Descubra tendências, salários e skills mais buscadas na área de tecnologia, com ferramentas práticas, dicas de especialistas, trilhas para entrevistas e live exclusiva do Talent Lab.

Por que aprender Design Patterns? Os benefícios na prática

Quadro branco com anotações de planejamento de projeto de software, incluindo fases de "Design" e "Dev", com post-its e diagramas. Ilustra a complexidade da arquitetura de software.

O planejamento de um software muitas vezes revela padrões de desafios. Design Patterns são as soluções consagradas para esses problemas recorrentes, trazendo clareza e eficiência ao processo.

No mercado de trabalho, a “fluência” em Design Patterns é um grande diferencial. 

Muitas vezes, mesmo sem conhecer a teoria, profissionais com mais tempo de casa já aplicam conceitos de padrões intuitivamente. No entanto, conhecê-los formalmente traz vantagens claras:

  • Vocabulário comum: Facilita a comunicação na equipe. Em vez de explicar uma solução complexa por dez minutos, você pode simplesmente dizer: "Vamos usar um padrão Strategy aqui". Todos que conhecem o padrão entenderão imediatamente a intenção.
  • Economia de tempo e esforço: Você não precisa "reinventar a roda". Os padrões são soluções otimizadas e testadas por milhares de pessoas ao redor do mundo. Eles ajudam a evitar armadilhas comuns que podem levar a um código difícil de manter.
  • Qualidade e manutenibilidade do código: Utilizar padrões resulta em um código mais organizado, flexível, reutilizável e fácil de entender por outras pessoas (ou por você no futuro).
  • Base para arquiteturas complexas: Eles são os "tijolos" fundamentais sobre os quais arquiteturas de software mais complexas são construídas.

E o SOLID? Onde se encaixa nessa história?

É muito comum que, ao estudar Design Patterns, você se depare com o termo SOLID

Embora estejam relacionados e sejam frequentemente estudados em conjunto, eles não são a mesma coisa.

SOLID é um acrônimo para cinco princípios de design para a programação orientada a objetos. Inclusive, aqui na Alura, o Paulo já trouxe um papo bem legal sobre o tema: 

Orientação a objetos com Roberta Arcoverde | #HipstersPontoTube

Eles são diretrizes de alto nível que, quando seguidas, tornam o software mais robusto, flexível e fácil de manter.

Pense nos princípios SOLID como as "leis da física" da boa arquitetura de software, enquanto os Design Patterns são as "plantas de engenharia" que utilizam essas leis para construir soluções específicas. 

Os padrões frequentemente aplicam um ou mais princípios SOLID em sua implementação.

Os cinco princípios são:

  • S - Single Responsibility Principle (Princípio da Responsabilidade Única): Uma classe deve ter um, e somente um, motivo para mudar.
  • O - Open-Closed Principle (Princípio Aberto-Fechado): Objetos devem estar abertos para extensão, mas fechados para modificação.
  • L - Liskov Substitution Principle (Princípio da Substituição de Liskov): Uma classe derivada deve ser substituível por sua classe base.
  • I - Interface Segregation Principle (Princípio da Segregação de Interface): Clientes não devem ser forçados a depender de interfaces que não utilizam.
  • D - Dependency Inversion Principle (Princípio da Inversão de Dependência): Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.

Quais são os Padrões de Projeto? As 3 categorias principais

A referência mais famosa e fundamental sobre o tema é o livro de 1994, "Design Patterns: Elements of Reusable Object-Oriented Software"

Por terem sido escritos por quatro autores (Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides), eles ficaram conhecidos como a Gang of Four (GoF)

Por isso, é muito comum ouvir a expressão "Quais são os padrões GoF?".

Neste livro, eles catalogaram 23 padrões clássicos, divididos em três categorias principais, de acordo com o tipo de problema que resolvem. 

Vamos explorar cada uma delas com exemplos.

1. Padrões criacionais (creational patterns)

Esses padrões lidam com os mecanismos de criação de objetos

Eles tentam criar objetos de uma maneira adequada para a situação, tornando o sistema mais flexível e independente de como seus objetos são criados, compostos e representados.

Singleton Design Pattern 

Este é um dos padrões mais conhecidos (e às vezes controverso). O singleton design pattern garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global para ela.

  • Problema: Você precisa ter exatamente um objeto de um tipo em todo o sistema. Por exemplo, uma classe que gerencia a conexão com um banco de dados ou as configurações de uma aplicação.
  • Solução: A classe se torna responsável por criar sua própria instância e garante que nenhuma outra instância seja criada.

Factory Method

Define uma interface para criar um objeto, mas deixa as subclasses decidirem qual classe instanciar.

  • Problema: Você tem uma classe que não pode antecipar o tipo de objetos que precisa criar. Imagine um aplicativo de logística que precisa criar objetos Transporte — pode ser um Caminhao, um Navio ou um Aviao.
  • Solução: Você cria um método "fábrica" que é implementado pelas subclasses (FabricaDeCaminhoes, FabricaDeNavios), cada uma retornando o objeto de transporte correto.

Builder

Permite construir objetos complexos passo a passo. O padrão permite que você produza diferentes tipos e representações de um objeto usando o mesmo código de construção.

  • Problema: Você precisa criar um objeto com muitos campos de configuração (alguns obrigatórios, outros opcionais), e um construtor com uma lista gigante de parâmetros seria impraticável.
  • Solução: Você cria um objeto Builder que recebe as configurações passo a passo (.comNome("X"), .comEndereco("Y")) e, ao final, chama um método .build() para retornar o objeto final, devidamente configurado.

2. Padrões estruturais (structural patterns)

Esses padrões explicam como montar objetos e classes em estruturas maiores, mantendo a flexibilidade e a eficiência da estrutura. 

Eles se concentram em como as classes e objetos são compostos para formar estruturas maiores e mais complexas.

Adapter

Permite que objetos com interfaces incompatíveis colaborem. É como um adaptador de tomada que permite que um plugue europeu funcione em uma tomada brasileira.

  • Problema: Você precisa usar uma classe de uma biblioteca externa, mas a interface dela não é compatível com o resto do seu código.
  • Solução: Você cria uma classe "adaptadora" que "envolve" o objeto incompatível e expõe uma interface que seu sistema entende.

Decorator

Permite adicionar novos comportamentos a objetos dinamicamente, colocando-os dentro de objetos "envoltórios" especiais que contêm os comportamentos.

  • Problema: Você quer adicionar responsabilidades extras a um objeto sem alterar sua classe. Imagine uma cafeteria onde você pode ter um café simples, um café com leite, um café com leite e chocolate, etc.
  • Solução: Você "decora" o objeto Cafe base com um DecoradorDeLeite e, em seguida, com um DecoradorDeChocolate, adicionando funcionalidades e custos em camadas.

Facade 

Fornece uma interface simplificada para uma biblioteca, um framework ou qualquer outro conjunto complexo de classes.

  • Problema: Você está trabalhando com um subsistema complexo que tem dezenas de classes e objetos que precisam ser inicializados e coordenados para realizar uma tarefa.
  • Solução: Você cria uma classe Facade (Fachada) que esconde toda essa complexidade interna e oferece alguns métodos simples para o cliente utilizar (ex: iniciarSistema(), desligarSistema()).

3. Padrões comportamentais (behavioral patterns)

Esses padrões se concentram nos algoritmos e na atribuição de responsabilidades entre os objetos. 

Eles descrevem não apenas padrões de objetos ou classes, mas também padrões de comunicação entre eles.

Strategy

Permite definir uma família de algoritmos, colocar cada um deles em uma classe separada e tornar seus objetos intercambiáveis.

  • Problema: Você tem uma tarefa que pode ser executada de várias maneiras diferentes. Por exemplo, calcular uma rota em um aplicativo de mapas pode usar a estratégia "caminho mais rápido", "caminho mais curto" ou "caminho sem pedágios".
  • Solução: Você define uma interface EstrategiaDeRota e cria classes concretas (RotaRapida, RotaCurta). O objeto principal (o Mapa) pode trocar de estratégia dinamicamente, sem alterar seu próprio código.

Observer

Permite definir um mecanismo de assinatura para notificar múltiplos objetos sobre quaisquer eventos que aconteçam com o objeto que eles estão observando.

  • Problema: Você tem um objeto (o "sujeito") cujo estado muda, e vários outros objetos (os "observadores") precisam ser notificados sobre essa mudança. Pense em uma planilha: quando você muda o valor de uma célula, todos os gráficos que dependem dela são atualizados automaticamente.
  • Solução: Os observadores se "inscrevem" no sujeito. Quando o estado do sujeito muda, ele percorre sua lista de observadores e chama um método de notificação em cada um deles.

Chain of responsibility 

Permite passar requisições ao longo de uma cadeia de manipuladores. Ao receber uma requisição, cada manipulador decide se processa a requisição ou se a passa para o próximo manipulador na cadeia.

  • Problema: Você tem uma série de verificações a serem feitas em uma requisição, como um sistema de aprovação de despesas: um gestor pode aprovar até R500,umdiretorateˊR5.000, e o CEO aprova valores maiores.
  • Solução: Você cria uma "corrente" de objetos (gestor -> diretor -> CEO). A requisição de despesa é passada ao primeiro elo. Se ele não puder aprová-la, passa para o próximo, e assim por diante.

Mais que soluções, uma forma de pensar

Conhecer e utilizar Design Patterns é um passo fundamental na jornada para se tornar uma pessoa desenvolvedora de software mais madura. 

Eles não são apenas soluções prontas, mas uma forma de pensar sobre problemas de software de maneira estruturada e colaborativa.

Ao dominar esses padrões, você não apenas escreve um código melhor, mas também se comunica de forma mais eficiente com sua equipe e constrói sistemas que estão preparados para crescer e evoluir.

Se você sentiu o interesse em se aprofundar e aprender na prática como aplicar esses conceitos, a Alura oferece o caminho ideal. 

Nossas formações são projetadas para transformar teoria em habilidade prática.

Quer levar seu código para o próximo nível e pensar como uma pessoa arquiteta de software? Explore os cursos de Design Patterns da Alura da Escola de Programação da Alura e construa soluções mais robustas e elegantes!

Igor Chagas
Igor Chagas

Estudante e entusiasta da linguagem Java, integrante do Scuba Team da Alura e universitário nas horas vagas.

Veja outros artigos sobre Programação