terça-feira, 22 de abril de 2008

O padrão Visitor

Enquanto vou brincando com o código, tentando organizar as classes de uma forma legal e intuitiva, me deparo sempre com dois problemas: aumento da complexidade e reescrita de código.
Da parte do aumento de complexidade, é mais o caso de experiencia mesmo.
A reescrita de código, tenho me deparado com um problema em particular: Eu crio objetos que representem sólidos. Alguns deles ficarão parados na tela, como paredes ou caixas. Outros sofrerão a ação da gravidade, do vento ou qualquer outra situação que altere o comportamento desses objetos.
Como coloquei a dois posts atrás, implementar essa gravida é bem simples, 1 linha no método Update() e está pronto. Para testar,criei uma classe de sólidos que caem e todas as que tivessem esse comportamento, herdariam dela, algo bem simples para começar. Dai começaram os "e se...?". Se para cada tipo de solido que eu quisesse criar, teria que criar uma nova classe e herdar dessa "objeto que cai". Quantas classes eu teria ao criar cada classe para um comportamento? Se eu quisesse que uma caixa caia?
Seria muito interessante se eu pudesse acoplar esse comportamento ao objeto quando eu quisesse. Se eu tenho uma caixa e quero que ela passe a cair, bastaria dar a ela esse comportamento e tudo funcionaria bem. Como não da para fazer herança múltipla, comecei a pesquisar nos padrões do gof por algum que me ajudasse a implementar isso. Por sorte, ele existe!
O padrão Visitor é uma solução para separar o algoritmo da estrutura. Uma das vantagens desse padrão é a habilidade de adicionar novas operações a uma estrutura já existente. Com ele, podemos ter a classe ObjetoSolido e o comportamento de queda em uma classe Gravidade, separada da estrutura do ObjetoSolido. Isso é feito através de uma interface, onde o objeto que vai executar esse método da classe do comportamento, passa uma referencia dela mesmo juto dos parâmetros normais da classe.
No caso desse exemplo, teríamos:

Visitor gravidade = new Gravidade(); //esse é o nosso visitor, responsável pelo comportamento de queda.
Solido solido = new Solido("caixa"); //solido que recebera o comportamento
solido.accept(gravidade); //recebe o comportamento Gravidade


Internamente, o método accept(Visitor visitor) de Solido faz o seguinte:

public void accept(Visitor visitor) {
visitor.visitSolido(this);
}

Ao passar para o Visitor uma referencia de si mesmo, o visitor pode acessar os métodos e atributos públicos dessa classe, que no nosso caso, vai adicionar a aceleração da gravidade ao Solido. Assim como o comportamento de queda foi adicionado, outros também poderiam ser feitos da mesma maneira, como movimentação através do teclado, sons... as possibilidades são infinitas.

Para quem quiser saber mais sobre o Visitor, segue o link (inglês): http://en.wikipedia.org/wiki/Visitor_pattern

Nenhum comentário: