Eu estava lendo este artigo e fiquei pensando: será que vamos nos livrar de todas as instruções de troca, substituindo-as por um Dicionário ou uma Fábrica, para que não haja nenhuma declaração de troca em meus projetos?
Algo não deu certo.
A questão é: as instruções switch têm algum uso real ou as substituímos por um dicionário ou um método factory (ao usar um método factory, é claro, haverá um uso mínimo das instruções switch para criar os objetos usando a fábrica ... mas é isso).
refactoring
switch-statement
Kanini
fonte
fonte
Respostas:
Ambas as
switch
afirmações e o polimorfismo têm seu uso. Observe que também existe uma terceira opção (em idiomas que suportam ponteiros de função / lambdas e funções de ordem superior): mapeando os identificadores em questão para funções de manipulador. Está disponível em, por exemplo, C, que não é uma linguagem OO, e C #, que é *, mas não (ainda) em Java, que também é OO *.Em algumas linguagens processuais (sem polimorfismo nem funções de ordem superior)
switch
/if-else
declarações eram a única maneira de resolver uma classe de problemas. Muitos desenvolvedores, acostumados a esse modo de pensar, continuaram a usarswitch
mesmo nas linguagens OO, onde o polimorfismo costuma ser uma solução melhor. É por isso que é frequentemente recomendado evitar / refatorarswitch
declarações em favor do polimorfismo.De qualquer forma, a melhor solução depende sempre do caso. A questão é: qual opção oferece um código mais limpo, conciso e mais sustentável a longo prazo?
As instruções de troca geralmente podem se tornar pesadas, tendo dezenas de casos, dificultando a manutenção. Como você precisa mantê-los em uma única função, essa função pode crescer muito. Se for esse o caso, considere refatorar para uma solução baseada em mapa e / ou polimórfica.
Se o mesmo
switch
começar a aparecer em vários lugares, o polimorfismo é provavelmente a melhor opção para unificar todos esses casos e simplificar o código. Especialmente se se espera que mais casos sejam adicionados no futuro; quanto mais lugares você precisar atualizar a cada vez, mais possibilidades de erros. No entanto, geralmente os manipuladores de casos individuais são tão simples, ou existem muitos deles, ou são tão inter-relacionados, que refatorá-los para uma hierarquia de classes polimórfica completa é um exagero ou resulta em muitos códigos duplicados e / ou emaranhados, difícil manter a hierarquia de classes. Nesse caso, pode ser mais simples usar funções / lambdas (se o seu idioma permitir).No entanto, se você tiver um
switch
em um único local, com apenas alguns casos fazendo algo simples, pode ser a melhor solução para deixá-lo como está.* Eu uso o termo "OO" aqui vagamente; Não estou interessado em debates conceituais sobre o que é OO "real" ou "puro".
fonte
É aqui que eu volto a ser um dinossauro ...
As declarações de switch não são ruins em si mesmas, é o uso que é feito delas que está em questão.
A mais óbvia é a declaração "switch" repetida várias vezes através de seu código que é ruim (esteve lá, fez isso, faria todos os esforços para não repetir) - e é este último caso que você pode lidar com o uso de polimorfismo. Geralmente, também há algo bastante horrível nos casos aninhados (eu costumava ter um monstro absoluto - não tenho muita certeza de como lidar com isso agora, a não ser "melhor").
Dicionário como opção, acho mais desafiador - fundamentalmente sim, se sua opção cobre 100% dos casos, mas onde você deseja ter casos de ação padrão ou sem ação, ela começa a ficar um pouco mais interessante.
Acho que é uma questão de evitar repetições e garantir que estamos compondo nossos gráficos de objetos nos lugares certos.
Mas há também o argumento de compreensão (manutenibilidade) e isso corta nos dois sentidos - depois que você entende como tudo funciona (o padrão e o aplicativo em que é implementado) é fácil ... mas se você chegar a uma única linha de código em que Para adicionar algo novo, é preciso pular por todo o lado para descobrir o que você precisa adicionar / alterar.
Por tudo o que nossos ambientes de desenvolvimento são massivamente capazes, ainda sinto que é desejável entender o código (como se fosse) impresso no papel - você pode seguir o código com o dedo? Aceito que, na verdade, não, com muitas práticas recomendadas hoje em dia, você não pode e por boas razões, mas isso significa que é mais difícil começar a se familiarizar com o código (ou talvez eu esteja velho ...)
fonte
Instruções de comutação versus polimorfismo de subtipo é um problema antigo e é frequentemente referido na comunidade FP em discussões sobre o Problema da Expressão .
Basicamente, temos tipos (classes) e funções (métodos). Como codificamos as coisas para facilitar a adição de novos tipos ou métodos?
Se você programar no estilo OO, é difícil adicionar um novo método (pois isso significaria refatorar todas as classes existentes), mas é muito fácil adicionar novas classes que usem os mesmos métodos de antes.
Por outro lado, se você usar uma instrução switch (ou seu equivalente OO, o Observer Pattern), é muito fácil adicionar novas funções, mas é difícil adicionar novos casos / classes.
Não é fácil ter uma boa extensibilidade em ambas as direções; portanto, ao escrever seu código, determine se deve usar polimorfismo ou alternar instruções, dependendo de qual direção você tem mais chances de estender.
fonte
Não. Esses absolutos raramente são uma boa idéia.
Em muitos lugares, um despacho de dicionário / pesquisa / fábrica / polimórfico fornecerá um design melhor que uma instrução switch, mas você ainda precisará preencher o dicionário. Em certos casos, isso obscurecerá o que realmente está acontecendo e simplesmente manter a instrução switch alinhada é mais legível e sustentável.
fonte
Vendo como isso é independente de idioma, o código de resultado funciona melhor com as
switch
instruções:Equivalente a
if
, com um caso padrão muito estranho. E lembre-se de que quanto mais falhas houver, mais longa será a lista de condições:(No entanto, considerando o que algumas das outras respostas dizem, sinto que perdi o objetivo da pergunta ...)
fonte
switch
como estando no mesmo nível que umgoto
. Se o algoritmo a ser executado exigir fluxos de controle que se encaixam nas construções de programação estruturada, deve-se usar essas construções, mas se o algoritmo não se encaixar nessas construções, o usogoto
pode ser melhor do que tentar adicionar sinalizadores ou outra lógica de controle para caber em outras estruturas de controle .As instruções de switch como diferenciação de caso têm um uso real. As linguagens de programação funcional usam algo chamado correspondência de padrões, que permite definir funções de maneira diferente, dependendo da entrada. No entanto, nas linguagens orientadas a objetos, o mesmo objetivo pode ser alcançado de maneira mais elegante usando o polimorfismo. Você simplesmente chama o método e, dependendo do tipo real do objeto, a implementação correspondente do método será executada. Esta é a razão por trás da ideia, que as instruções de switch são um cheiro de código. No entanto, mesmo em idiomas OO, você pode encontrá-los úteis para implementar o padrão abstrato de fábrica.
tl; dr - eles são úteis, mas muitas vezes você pode fazer melhor.
fonte