C#
- Princípio DRY (revisitado)
![]() |
Hoje vamos recordar o princípio DRY - Don´t Repeat Yourself |
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:
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:
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 { get; set; } public double Altura { get; set; } 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 { get; set; } public double Altura { get; set; } public virtual double CalcularArea() { return Largura * Altura; } } public
class
Quadrado
: Figura |
Neste exemplo, inicialmente temos duas classes,
Retangulo
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
.
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.PI
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
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
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.
"Seja, porém, o vosso falar: Sim, sim; não, não; porque o que passa disto é
procedente do mal."
Mateus 5:37
Referências: