![]() |
Hoje vamos discutir a questão : A utilização da instrução switch da linguagem C# seria considerado um má prática de programação ? |
A instrução switch/case é usada para operações condicionais e às vezes o seu uso pode ser considerado um má prática fazendo com que o código 'não cheire bem' (code smell).
Na verdade não podemos ser tão rigorosos a ponto de dizer que nunca devemos usar a instrução switch/case, mas seu uso deve ser feito com muito cuidado principalmente na programação orientada a objetos.
Dependendo do cenário, quando usada na programação orientada a objetos a instrução switch/case pode causar os seguintes problemas :
switch(input) { case "a": CriarValor("Bom dia"); data+= "Bom dia"; case "b":
case "C":
default:
|
Assim de forma geral usar a instrução switch com valores primitivos não causa tanto problemas mas usá-la com tipos e objetos não é uma boa prática.
Como refatorar um código que esta usando switch/case
Na maioria dos cenários a instrução switch/case pode ser refatorada usando polimorfismo e/ou o padrão Strategy.
Para exemplificar vamos analisar o trecho de código a seguir:
List<string> GetDadosOrdenados(string
tipo, List<string> dados) { List<string> resultado = null;
switch (tipo)
case "HeapSort":
case "MergeSort":
case "InsertionSort":
return resultado; |
Neste código estamos realizando a ordenação dos dados recebidos com base no tipo de ordenação selecionado. Temos aqui os seguintes problemas:
Assim se for preciso um novo tipo de ordenação, teremos que modificar o método, incluindo mais responsabilidades e lógica e estaremos alterando o código existente violando o princípio Open Closed.
Para eliminar este 'mau cheiro' deste código podemos usar polimorfismo, o padrão Stratey e a correspondência de padrões.
Primeiro vamos definir uma interface IOrdenacao que vai definir um contrato para realizar a ordenação e retornar os dados ordenados:
public interface IOrdenacao { List<string> GetDadosOrdenados(List<string> dados); } |
A seguir vamos implementar cada tipo de ordenação usando esta interface. Assim iremos criar as seguintes classes concretas que implementa a interface IOrdenacao :
public class HeapSort : IOrdenacao { public List<string> GetDadosOrdenados(List<string> dados) { Console.WriteLine("HeapSort"); return dados; } } public class MergeSort : IOrdenacao public class InsertionSort : IOrdenacao |
Nota: A implementação de cada método não foi feita para simplificar o exemplo.
A seguir vamos criar a classe OrdenacaoContext onde vamos usar um Dictionary para definir a lógica de instanciar a classe de ordenação conforme o tipo selecionado :
public class OrdenacaoContext { private Dictionary<string, IOrdenacao> ordenacaoStrategy = new Dictionary<string, IOrdenacao>();
public OrdenacaoContext() public List<string> GetDadosOrdenados(string tipo, List<string> dados) |
Podemos testar a refatoração feita usando o código abaixo:
List<string> data = new List<string> { "Banana", "Abacaxi", "Caju", "Laranja", "Abacate", "Manga" }; OrdenacaoContext ordenacaoContext = new OrdenacaoContext(); List<string> result = ordenacaoContext.GetDadosOrdenados("BubbleSort", data); Console.ReadKey(); |
Com isso temos a refatoração do código.
Desta forma a instrução switch/case é uma declaração condicional que pode ser usada em avaliações numéricas mas quando aplicada a objetos e tipos vai ferir alguns princípios SOLID e causar um mal cheiro no código, e, isso pode ser resolvido usando polimorfismo e o padrão strategy.
Código usado: switch_refatora.txt
E estamos conversados.
"Porque foi do
agrado do Pai que toda a plenitude nele habitasse,
E que, havendo por ele feito a paz pelo sangue da sua cruz, por meio dele
reconciliasse consigo mesmo todas as coisas, tanto as que estão
na terra, como as que estão nos céus."
Colossenses
1:19,20
Referências:
C# - Lendo e escrevendo em arquivos textos e binários
C# - Entendo o I/O na plataforma .NET
C# - Fluxo assíncrono ou async streams
C#- Apresentando Streams assíncronos