24 Set, 2009 14:40

Programando para Windows Mobile usando MVC e Delegates - Parte 2

De acordo com algumas literaturas, a implementação do padrão MVC especifica que o modelo notifique a view em caso de alterações, de forma que os dados exibidos na view sejam atualizados.

Diagrama do modelo MVC

Para fazer essa notificação, vamos ampliar um pouco mais o conceito de delegates, passado no primeiro post, e utilizar também eventos.

Na verdade, para os mais atentos, o conceito de evento já foi utilizado no post anterior, quando eu criei o seguinte método na view para adicionar um delegate:

public void AddSalvarClick(ViewEventsDelegate metodo) {
    BtnSalvar.Click += new EventHandler(metodo);
}

Estávamos na verdade dizendo que o evento Click do botão BtnSalvar iria acionar o método passado por ele por parâmetro. Assim, fica mais fácil entender o funcionamento de um evento:

  • Os eventos são os "gatilhos" para os delegates: quando um evento é chamado, os métodos adicionados a ele são chamados;

  • Os eventos não aceitam qualquer tipo de delegate: ao declarar um evento, você deve especificar qual o tipo de delegate está associado a ele. De uma forma direta, isso implica dizer que os eventos só aceitam os métodos com a assinatura especificada na declaração do delegate.

Voltemos ao nosso exemplo. Como disse acima, a implementação do padrão em camadas pede a notificação da view em caso de alteração no modelo. Mas aqui é necessário pensar um pouco na forma como essa notificação vai ser feita, principalmente no que diz respeito ao modo como a informação a ser alterada será passada para a view. Em alguns textos, ao notificar a view, o objeto de modelo passa como parâmetro ele mesmo, e a view pega então todos os valores do modelo e preenche. O problema que alguns podem ver aqui é o da acoplagem, pois eu estaria prendendo a classe view a um tipo específico de modelo. Uma solução alternativa seria criar notificações para várias alterações, passando então o valor (geralmente em tipos básicos como strings, inteiros, etc) só do que está sendo alterado.

Não sou puritano, mas acho as duas abordagens válidas. A vantagem da segunda - além da baixa acoplagem - é reduzir para métodos pequenos a alteração do conteúdo. Tenho certo medo de métodos do tipo AlteraTudo(object modelo), por ter séria tendência a se tornar um método frankenstein, difícil de dar manutenção.

Vamos ao código! Em um exemplo fictício, onde tenho um sistema de venda de livros, um modelo óbvio seria um Livro. Vou criar nesse exemplo um evento que trata a notificação da alteração do preço do livro. Quando o preço for alterado, ele notifica a todos aqueles que "assinaram" o evento.

  namespace PostMVC {
      //declarando o delegate
      public delegate void PriceChangeDelegate(float price);

      class Book {

          //criando o evento
          private event PriceChangeDelegate OnPriceChange;

          //metodo que adiciona delegates ao evento do preco
          public void AddPriceChangeDelegate(PriceChangeDelegate priceDelegate) {
              OnPriceChange += priceDelegate;
          }

          //o atributo preco
          private float _price;

          // Get e Set do campo preço. Perceba que no set eu chamo o 
          //evento que sera executado por causa da alteracao feita
          public float Price {
              get { return _price; }
              set {
                  _price = value;
                  if (OnPriceChange != null)
                      OnPriceChange(value);
              }
          }
      }
  }

Percebam a validação feita antes de executar o evento:

  if (OnPriceChange != null)
        OnPriceChange(value);

Um evento é nulo se nenhum delegate está associado a ele. Agora, na view, o código fica bem simples: basta adicionar um método que tenha a assinatura do delegate especificada, que faça essa alteração:

  public void AlteraPrecoNaTela(float preco) {
        //codigo que escreve na tela
  }

E no construtor também fica bem tranquila a implementação:

  class BookController {
        private Book model;
        private BookPriceForm view;

        //construtor
        BookController() {
              model = new Book();
              view = new BookPriceForm();

              model.AddPriceChangeDelegate(view.AlteraPrecoNaTela);
        }
  }

Com isso, o único que fica acoplado é o controller, que é quem realmente tem que ter os modelos e as vistas.

Dessa forma, você evita colocar o código todo no formulário, você traz a sua lógica de negócio para o controlador, seu código fica mais simples, mais fácil dar manutenção, e todos ficam felizes! :)

Ao navegar neste site, você consente o uso de cookies nossos e de terceiros, que coletam informações anônimas e são essenciais para melhorar sua experiência em nosso site.