Padrão de visitante genérico em java

A seguinte implementação de java do padrão de visitante é feita usando genéricos, geral o suficiente para ser útil? (Eu suponho que é).

Poderia ser melhorado de alguma forma? É importante poder chamar facilmente usando classs anônimas. Obrigado.

(Exemplo de uso):

Vector numbers = new Vector(); numbers.add(new Double(1.2)); numbers.add(new Float(-1.2)); numbers.add(new Double(4.8)); numbers.add(new Float(-3.4)); numbers.add(new Long(123456)); numbers.add(new Short("14")); For.each(numbers, new Visitor() { public void doIt(Double n) { System.out.println("doIt() for double: " + n); } public void doIt(Float n) { System.out.println("doIt() for float: " + n); } public void doIt(Number n) { System.out.println("doIt() for Number: " + n); } }); Visitor visi = new Visitor() { private StringBuffer all = new StringBuffer (); public void doIt(Number n) { System.out.println("doIt() for Number: " + n); all.append(n.toString() + " "); } public Object getResult () { return all; } }; For.each(numbers, visi); System.out.println ("all -> " + visi.getResult()); 

Definições:

 //............................................ abstract class Visitor { public void visit(T n) { try { this.getClass().getDeclaredMethod("doIt", n.getClass()).invoke(this, n); } catch (Exception ex) { doIt((T) n); } } public void doIt(T n) { System.out.println("doIt() for base " + n); } public Object getResult() { return null; } } // class //............................................ class For { public static  void each (Collection c, Visitor f) { for (T v : c) { f.visit(v); } } // () } // class 

Este não é o padrão de visitantes .

Visitante é caracterizado pela visita ter um método de accept(Visitor v) que interage com um método de visita no visitante tomando como parâmetro a visitada e sobrecarregada pelo tipo variado da visita, formando um mecanismo de “duplo despacho”.

Citando a seção “Aplicabilidade” para Visitante em Padrões de Design :

Use o padrão Visitante quando

  • Uma estrutura de objects contém muitas classs de objects com interfaces diferentes e você deseja executar operações nesses objects que dependem de suas classs concretas.
  • muitas operações distintas e não relacionadas precisam ser executadas em objects em uma estrutura de object e você deseja evitar “poluir” suas classs com essas operações. O Visitante permite manter as operações relacionadas juntas, definindo-as em uma class. Quando a estrutura do object é compartilhada por muitos aplicativos, use o Visitor para colocar operações apenas nos aplicativos que precisam deles.
  • as classs que definem a estrutura do object raramente mudam, mas geralmente você deseja definir novas operações na estrutura. Alterar as classs da estrutura do object requer redefinir a interface para todos os visitantes, o que é potencialmente caro. Se as classs da estrutura do object forem alteradas com frequência, provavelmente será melhor definir as operações nessas classs.

Portanto, esse padrão é para lidar com operações semelhantes em objects de vários tipos. Em seus exemplos, os objects que você está chamando visitantes só podem lidar com um tipo.

Em sua resposta revisando para usar a reflection para lidar com vários tipos (que, a propósito, seria melhor feito como uma edição para a pergunta ou como uma questão separada), você está evitando criar um método de accept(Visitor v) nas classs visitadas por usando a reflection, que até certo ponto está realizando o mesmo objective, mas um pouco desajeitadamente. Eu ainda resistiria a chamá-lo de uma implementação do Visitor.

Se o código no estilo que você escreveu aqui é útil para você, use-o, mas não o chame de Visitante.

Isso é mais como um padrão de estratégia ou um object de function , e se você renomear a class genérica de uma maneira que reflita isso, na verdade é útil, e seu uso é semelhante aos padrões comuns de manipulação de lista em linguagens funcionais.

O que eu provavelmente faria com o código da questão é renomear seu Visitor para Operation e renomear sua visit(T t) para execute(T t) ou apply(T t) , pensando em uma Operation como um Function sem um valor de retorno. De fato, usei exatamente isso de maneira semelhante ao que você está fazendo, e usei táticas similares para o mapeamento de coleção usando objects genéricos Function . Não tenho certeza de qual nome de padrão realmente se encheckbox, mas não é Visitante. Está trazendo um estilo funcional de compreensão de lista para um mundo OO onde as funções não são naturalmente objects de primeira class.

Graças à resposta de donoby sobre o meu código inicial não implementando o padrão de visitante, cheguei a esta nova versão.

Suponho que agora implemente o padrão de visitante sem a necessidade de modificar o elemento visitado com um método accept (). De qualquer forma, é possível chamar o método correto, dependendo do tipo de elemento (acho que essa é a missão do accept ()), graças à reflection.

Primeiro, um exemplo de uso:

 Vector numbers = new Vector(); numbers.add(new Double(1.2)); numbers.add(new Float(-1.2)); numbers.add(new Double(4.8)); numbers.add(new Float(-3.4)); numbers.add(new Long(123456)); numbers.add(new Short("14")); For.each(numbers, new Visitor() { public void doIt(Double n) { System.out.println("doIt() for double: " + n); } public void doIt(Float n) { System.out.println("doIt() for float: " + n); } public void doIt(Number n) { System.out.println("doIt() for Number: " + n); } }); 

Isso produz esta saída

 doIt () para o dobro: 1.2
 doIt () para float: -1.2
 doIt () para o dobro: 4.8
 doIt () para float: -3,4
 doIt () para número: 123456
 doIt () para o número: 14

E finalmente o código

 abstract class Visitor { public void visit(T n) { try { this.getClass().getDeclaredMethod("doIt", n.getClass()).invoke(this, n); } catch (Exception ex) { doIt((T) n); } } public void doIt(T n) { System.out.println("doIt() for base " + n); } public Object getResult() { return null; } 

}

 class For { public static  void each (Collection c, Visitor f) { for (T v : c) { f.visit(v); } } // () 

}

e quanto a

  for(String s : words) System.out.println (s.toUpperCase()); int total = 0; for(String s : words) total = total + s.length(); System.out.println (" sum of lengths = " + total);