.NET

5 jun, 2026

C# – Princípio DRY

Publicidade

O princípio DRY (Don’t Repeat Yourself) é um princípio de desenvolvimento de software que promove a eliminação de duplicação de código e enfatiza a importância de evitar a repetição desnecessária de informações ou lógica em um sistema, pois a duplicação de código pode levar a problemas de manutenção, aumento da complexidade e inconsistências.

O princípio DRY pode ser resumido pela seguinte frase: Toda parte do conhecimento deve ter uma representação única, não ambígua e autoritativa no sistema”.

 Este princípio foi popularizado pelo livro “The Pragmatic Programmer” de Andrew Hunt e David Thomas.

Aqui estão algumas informações sobre como o princípio DRY atua, como funciona, como pode ser usado e onde pode ser aplicado:

  1. Evitar duplicação: O princípio DRY visa eliminar a duplicação de código, seja em forma de repetição literal de trechos de código, repetição de lógica semelhante ou redundância de informações. Ao evitar a duplicação, o código se torna mais conciso, fácil de manter e menos propenso a erros.
  2. Centralização do conhecimento: O DRY incentiva a centralização do conhecimento em um único lugar no sistema. Em vez de ter a mesma lógica espalhada em vários lugares, é preferível ter um único local onde a lógica é definida e referenciada sempre que necessário. Isso facilita a manutenção e evita inconsistências.
  3. Reutilização de código: O DRY promove a reutilização de código existente. Em vez de duplicar código, é preferível criar abstrações ou componentes reutilizáveis que possam ser compartilhados em diferentes partes do sistema. Dessa forma, uma única alteração nesses componentes afeta todas as suas instâncias.
  4. Simplificação e legibilidade: Ao eliminar a duplicação, o código se torna mais simples, conciso e legível. A lógica é expressa em um único lugar, o que facilita a compreensão e a depuração. Além disso, alterações futuras são mais fáceis de serem feitas, pois só precisam ser aplicadas em um único local.

O princípio DRY pode ser aplicado em diversos níveis no desenvolvimento de software, desde a granularidade do código até a arquitetura do sistema. Alguns exemplos de onde o DRY pode ser usado incluem:

  • Evitar a repetição de blocos de código semelhantes em várias partes do sistema.
  • Utilizar funções, métodos ou classes reutilizáveis para evitar duplicação de lógica.
  • Centralizar informações comuns em constantes, enums ou configurações.
  • Usar herança, interfaces ou composição para compartilhar funcionalidades entre diferentes classes.
  • Refatorar trechos de código duplicados para criar abstrações e componentes reutilizáveis.

A seguir temos alguns exemplos básicos mostrando o uso deste princípio:

1: Evitar duplicação de código

// Exemplo não DRY
public void CalcularAreaCirculo(double raio)
{
double area = Math.PI * raio * raio;
Console.WriteLine(
“A área do círculo é: “ + area);
}
public void CalcularPerimetroCirculo(double raio)
{
double perimetro = 2 * Math.PI * raio;
Console.WriteLine(
“O perímetro do círculo é: “ + perimetro);
}

DRY :

// Exemplo DRY
public
 void CalcularCirculo(double raio)
{
double area = Math.PI * raio * raio;
double perimetro = 2 * Math.PI * raio;
Console.WriteLine(
“A área do círculo é: “ + area);
Console.WriteLine(
“O perímetro do círculo é: “ + perimetro);
}

No exemplo acima, inicialmente temos duas funções separadas para calcular a área e o perímetro de um círculo. Isso resulta em duplicação de código.

No exemplo DRY, a duplicação é eliminada, criando uma única função CalcularCirculo que calcula tanto a área quanto o perímetro. Isso reduz a repetição de código e facilita a manutenção, já que qualquer alteração na fórmula do círculo precisa ser feita em um único local.

2: Centralizar informações comuns

// Exemplo não DRY
public
 void ExibirErro(string mensagem)
{
Console.WriteLine(
“Erro: “ + mensagem);
}
public void ExibirAviso(string mensagem)
{
Console.WriteLine(
“Aviso: “ + mensagem);
}
public void ExibirInformacao(string mensagem)
{
Console.WriteLine(
“Informação: “ + mensagem);
}

Usando DRY:

// Exemplo DRY
public
 void ExibirMensagem(string tipo, string mensagem)
{
Console.WriteLine(tipo + 
“: “ + mensagem);
}

Neste exemplo, inicialmente temos três funções separadas para exibir diferentes tipos de mensagens (erro, aviso e informação). Isso resulta em duplicação de código.

No exemplo DRY, a duplicação é evitada, criando uma única função ExibirMensagem que recebe um parâmetro adicional indicando o tipo de mensagem a ser exibida. Isso centraliza a lógica comum e reduz a repetição de código.

3: Reutilização de código com herança

// Exemplo não DRY
public
 class Retangulo
{
public double Largura { getset; }
public double Altura { getset; }
public virtual double CalcularArea()
{
return Largura * Altura;
}
}
public class Quadrado : Retangulo
{
public override double CalcularArea()
{
return Largura * Largura;
}
}

Usando DRY:

public class Figura
{
public double Largura { getset; }
public double Altura { getset; }
public virtual double CalcularArea()
{
return Largura * Altura;
}
}
public class Quadrado : Figura
{
public override double CalcularArea()
{
return Largura * Largura;
}
}

Neste exemplo, inicialmente temos duas classes, Retangulo e Quadrado, onde Quadrado herda de Retangulo. No entanto, essa hierarquia não segue o princípio DRY, pois há duplicação de código na implementação de CalcularArea.

No exemplo DRY, a duplicação é evitada, criando uma classe base Figura que contém as propriedades Largura e Altura, bem como a implementação comum de CalcularArea. A classe Quadrado herda de Figura e substitui apenas o método necessário, mantendo o código mais limpo e reutilizando a lógica da classe base.

4- Utilizar constantes em vez de valores literais repetidos

// Exemplo não DRY
public
 double CalcularCircunferencia(double raio)
{
return 2 * Math.PI * raio;
}
public double CalcularAreaCirculo(double raio)
{
return Math.PI * raio * raio;
}

usando DRY:

private const double Pi = Math.PI;public double CalcularCircunferencia(double raio)
{
return 2 * Pi * raio;
}
public double CalcularAreaCirculo(double raio)
{

return
 Pi * raio * raio;
}

Neste exemplo, inicialmente temos duas funções que calculam a circunferência e a área de um círculo. Ambas as funções repetem o valor de Math.PINo exemplo DRY, o valor de Math.PI é armazenado em uma constante Pi, evitando a repetição desnecessária.

5- Utilizar herança para compartilhar comportamento comum

// Exemplo não DRY
public
 class Animal
{
public virtual void EmitirSom()
{
Console.WriteLine(
“O animal emite um som.”);
}
}
public class Gato : Animal
{
public override void EmitirSom()
{
Console.WriteLine(
“O gato mia.”);
}
}
public class Cachorro : Animal
{
public override void EmitirSom()
{
Console.WriteLine(
“O cachorro late.”);
}
}

usando DRY:

public abstract class Animal
{
public abstract void EmitirSom();
}
public class Gato : Animal
{
public override void EmitirSom()
{
Console.WriteLine(
“O gato mia.”);
}
}

public
 class Cachorro : Animal
{
public override void EmitirSom()
{
Console.WriteLine(
“O cachorro late.”);
}
}

Aqui, inicialmente temos uma classe base Animal e subclasses Gato e Cachorro, onde cada animal emite um som específico. No exemplo DRY, a classe base Animal é definida como abstrata, com um método abstrato EmitirSom().

As subclasses Gato e Cachorro herdam de Animal e fornecem suas próprias implementações do método EmitirSom(). Dessa forma, o comportamento comum é compartilhado através da herança, evitando duplicação desnecessária de código.

6- Utilizar métodos genéricos para evitar repetição de código similar

// Exemplo não DRY
public
 void ImprimirInteiros(List<int> numeros)
{
foreach (int numero in numeros)
{
Console.WriteLine(numero);
}
}
public void ImprimirStrings(List<string> strings)
{
foreach (string str in strings)
{
Console.WriteLine(str);
}
}

usando DRY:

public void ImprimirElementos<T>(List<T> elementos)
{
foreach (T elemento in elementos)
{
Console.WriteLine(elemento);
}
}

Neste exemplo, inicialmente temos duas funções que imprimem elementos de listas específicas: uma para inteiros e outra para strings.

No exemplo DRY, a duplicação é evitada usando um método genérico ImprimirElementos<T>() que aceita uma lista de qualquer tipo T e itera sobre os elementos para imprimi-los. Isso elimina a necessidade de escrever métodos separados para cada tipo específico.

Esses exemplos demonstram diferentes maneiras de aplicar o princípio DRY em código C#. O objetivo é evitar a duplicação desnecessária de código, centralizar informações comuns, compartilhar comportamentos similares e utilizar abstrações adequadas para promover a reutilização de código. Isso resulta em um código mais conciso, legível e fácil de manter.

E estamos conversados.