Estou construindo um simulador que analisa alguns eventos STDIN
e os "executa". Atualmente, minha formação é principalmente a programação funcional, por isso parecia natural fazer algo assim:
data Event = Thing1 String Int | Thing2 Int | Thing3 String String Int
Parse :: String -> [Event]
Simulate :: [Event] -> [Result]
onde simular seria
case event
of Thing1 a b => compute for thing one
| Thing2 a => compute for thing two
etc. Qual é a maneira idiomática de fazer esse tipo de coisa em Java? O Google me apontou na direção de classes aninhadas e do padrão de visitantes, mas isso parece bastante pesado na minha tentativa. O apagamento de tipo parece estar lutando comigo, com força. Você poderia me mostrar um resumo de como isso seria feito corretamente?
Event
tipo é conceitualmente equivalente a ter umInt
e doisMaybe Strings
?Respostas:
O autor de 'Functional Programming in Scala' fornece uma boa ilustração do melhor que pode ser alcançado em Java de uma maneira segura:
http://blog.higher-order.com/blog/2009/08/21/structural-pattern-matching-in-java/
Essencialmente, ele usa uma codificação da Igreja dos casos para garantir que o compilador irá reclamar, se houver algum.
Os detalhes não são facilmente resumidos e de fato são tão bem coberto no artigo que não há nenhum ponto em reproduzi-los aqui (que é o que hyperlinks são para certo?).
fonte
t.match
os três métodos, em vez de passar três funções. (Artigo ligado confunde padrão Visitor com o dobro da expedição - visitante é um padrão para abstrair a iteração através de uma rede, e não para a seleção em padrões)public static int depth(Tree t)
onde ele usa encadeado se uma instância de quando a maneira 'certa' de fazer isso em Java é definir uma interface com o método:public int depth()
e use polimorfismo. Parece um homem de palha.Realmente não existe, dado que Java (a linguagem) é fundamentalmente imperativo.
Se você puder executar na JVM, mas não se restringir à linguagem Java , poderá investigar o Scala, que alcançaria algo parecido com o acima, usando a correspondência de padrões .
Caso contrário, acho que você está reduzido a corresponder manualmente seus vários casos e chamar métodos conforme apropriado, ou talvez definir subtipos de 'Event' e usar o polimorfismo para invocar métodos específicos para cada subtipo.
fonte
Dê uma olhada em https://github.com/johnlcox/motif, que é uma biblioteca de "correspondência de padrões" semelhante a Scala para Java 8.
Não é tão bom quanto ML / Erlang / Haskell, mas ainda parece muito mais declarativo do que a maioria.
fonte
Você pode usar uma enumeração e uma interface, substituindo o método simular, assim:
Digamos que você tenha
Event event
. Em seguida, você pode usá-lo de duas maneiras:ou
Mas o construtor é chamado automaticamente pela JVM, para também armazenar os parâmetros, você precisará adicionar propriedades aos acessadores, etc.
Como alternativa, você pode codificar seus eventos como seqüências constantes e usar a
switch
construção. Nesse caso, você fariaetc. Mas sim, não há nada nativo que imite diretamente a correspondência de padrões :(
fonte
O padrão de visitantes ou seu equivalente de codificação de igreja é o caminho a seguir. É bastante detalhado em Java, mas espero que ferramentas como Derive4J (um processador de anotação que mantenho) ou Adt4J possam gerar o clichê. Usando essa ferramenta, seu exemplo se torna:
Derive4J gera a classe Events que fornece uma sintaxe fluente de correspondência de padrões (com verificação exaustiva de que todos os casos são tratados).
fonte