Desculpe, não consigo encontrar uma pergunta respondendo a esta, tenho quase certeza de que outra pessoa a levantou antes.
Meu problema é que estou escrevendo algumas bibliotecas do sistema para executar dispositivos incorporados. Tenho comandos que podem ser enviados a esses dispositivos por meio de transmissões de rádio. Isso só pode ser feito por texto. dentro das bibliotecas do sistema, eu tenho um thread que lida com os comandos que se parecem com este
if (value.equals("A")) { doCommandA() }
else if (value.equals("B")) { doCommandB() }
else if etc.
O problema é que há muitos comandos para que ele rapidamente se torne algo fora de controle. Horrível de olhar, doloroso de depurar e incompreensível de entender em alguns meses.
Respostas:
usando o padrão de comando :
em seguida, crie um
Map<String,Command>
objeto e preencha-o comCommand
instâncias:então você pode substituir sua corrente if / else if por:
EDITAR
você também pode adicionar comandos especiais como
UnknownCommand
ouNullCommand
, mas precisa de umCommandMap
que trate desses casos complicados para minimizar as verificações do cliente.fonte
Minha sugestão seria uma espécie de combinação leve de enum e objeto Command. Este é um idioma recomendado por Joshua Bloch no item 30 de Effective Java.
Claro, você pode passar parâmetros para doCommand ou ter tipos de retorno.
Esta solução pode não ser realmente adequada se as implementações de doCommand não se "ajustarem" realmente ao tipo enum, que é - como de costume quando você tem que fazer uma troca - um pouco confuso.
fonte
Tenha um enum de comandos:
Se você tiver mais do que alguns comandos, procure usar o padrão Command, conforme respondido em outro lugar (embora você possa manter o enum e incorporar a chamada à classe de implementação dentro do enum, em vez de usar um HashMap). Por favor, veja a resposta de Andreas ou jens a esta pergunta para um exemplo.
fonte
Implementar uma interface conforme demonstrado de forma simples e clara pelo dfa é limpo e elegante (e uma forma com suporte "oficial"). É para isso que se destina o conceito de interface.
Em C #, poderíamos usar delegados para programadores que gostam de usar ponteiros de função em c, mas a técnica do DFA é a maneira de usar.
Você também poderia ter um array
Então você pode executar um comando por índice
Plagiando do DFA, mas tendo uma classe base abstrata em vez de uma interface. Observe o cmdKey que seria usado posteriormente. Por experiência, percebo que frequentemente um comando de equipamento também possui subcomandos.
Construa seus comandos assim,
Você poderia então estender HashMap ou HashTable genérico fornecendo uma função de sucção de par de valores-chave:
Em seguida, construa seu armazenamento de comando:
Agora você pode enviar controles objetivamente
fonte
Bem, eu sugiro criar objetos de comando e colocá-los em um hashmap usando a String como chave.
fonte
Mesmo que eu acredite que a abordagem do padrão de comando é mais voltada para as melhores práticas e manutenção a longo prazo, aqui está uma opção de linha única para você:
org.apache.commons.beanutils.MethodUtils.invokeMethod (this, "doCommand" + valor, nulo);
fonte
Eu geralmente tento resolver dessa forma:
isso tem muitas vantagens:
1) não é possível adicionar um enum sem implementar exec. então você não vai perder um A.
2) você nem mesmo terá que adicioná-lo a nenhum mapa de comando, portanto, nenhum código clichê para construir o mapa. apenas o método abstrato e suas implementações. (que é indiscutivelmente também clichê, mas não ficará mais curto ..)
3) você salvará todos os ciclos de CPU desperdiçados, passando por uma longa lista de if's ou calculando hashCodes e fazendo pesquisas.
edit: se você não tem enums, mas strings como fonte, use
Command.valueOf(mystr).exec()
para chamar o método exec. observe que você deve usar o modificador público em exec se quiser chamá-lo de outro pacote.fonte
Você provavelmente está melhor usando um Mapa de Comandos.
Mas se você tiver um conjunto desses para lidar com você acaba com um monte de mapas batendo por aí. Então, vale a pena tentar fazer isso com Enums.
Você pode fazer isso com um Enum sem usar opções (provavelmente não precisa dos getters no exemplo), se adicionar um método ao Enum para resolver o "valor". Então você pode apenas fazer:
Update: adicionado mapa estático para evitar iteração em cada chamada. Desavergonhadamente tirado dessa resposta .
fonte
A resposta fornecida por @dfa é a melhor solução, na minha opinião.
Estou apenas fornecendo alguns trechos , caso você esteja usando Java 8 e queira usar Lambdas!
Comando sem parâmetros:
(você poderia usar um Runnable em vez de Command, mas não o considero semanticamente correto):
Comando com um parâmetro:
Caso você espere um parâmetro, pode usar
java.util.function.Consumer
:No exemplo acima,
doSomethingX
é um método presente namyObj
classe de que recebe qualquer Objeto (nomeadoparam
neste exemplo) como um argumento.fonte
se você tiver várias instruções 'if' imbricadas, esse é um padrão para usar um mecanismo de regras . Veja, por exemplo, JBOSS Drools .
fonte
Basta usar um HashMap, conforme descrito aqui:
fonte
se fosse possível ter uma série de procedimentos (o que você chamou de comandos) que seria útil.
mas você pode escrever um programa para escrever seu código. É tudo muito sistemático if (value = 'A') commandA (); else if (........................ etc
fonte
Não tenho certeza se há alguma sobreposição entre o comportamento de seus vários comandos, mas você também pode dar uma olhada no padrão Chain Of Responsibility, que pode fornecer mais flexibilidade, permitindo que vários comandos manipulem alguns valores de entrada.
fonte
O padrão de comando é o caminho a seguir. Aqui está um exemplo usando java 8:
1. Defina a interface:
2. Implemente a interface com cada uma das extensões:
e
e assim por diante .....
3. Defina o cliente:
4. E este é o resultado da amostra:
fonte
Se ele faz muitas coisas, então haverá muito código, você não pode realmente fugir disso. Apenas torne mais fácil seguir, dê às variáveis nomes muito significativos, comentários também podem ajudar ...
fonte