quinta-feira, 11 de junho de 2009

Padrões de Projeto: Observer

Os Padrões de Projeto são soluções genéricas para problemas recorrentes, “cada padrão descreve um problema no nosso ambiente e o cerne da solução, de tal forma que você possa usar essa solução mais de um milhão de vezes, sem nunca fazê-lo da mesma maneira”(Alexander, C. et al. apud Gamma, E. et al., 2000).

Ao utilizar um padrão de projeto na solução de um problema no desenvolvimento do software significa que optamos por uma solução de boa qualidade e já testada.

O padrão Observer é também conhecido como Publish-Subscribe, Event Generator ou Dependents (Salve, J.,2008). Esse padrão é endereçado a família de problemas que tem a intenção de “definir uma dependência um-para-muitos entre objetos, de maneira que quando um objeto muda de estado todos os seus dependentes são notificados e atualizados automaticamente” (Gamma, E. et al., 2000 ).

O padrão Observer que é aplicável quando a alteração no estado de um objeto implica em notificar ou alterar outros objetos. Além disso, os objetos que vão sofrer alteração ou ser notificados não são conhecidos pelo objeto que sofreu a mudança, conseguindo assim um fraco acoplamento.

No padrão Observer temos um objeto que será observado, chamado de Subject. Na API Java temos as classes java.util.Observable e java.swing.EventSource são implementações do Subject. Temos também o objeto que observa e é notificado chamado de Observer, em Java as classes que o implementam são java.util.Observer e o java.swing.Listener. Java usa o padrão na API de duas formas diferentes (Sauvé, J.,2006).



Download de uma implementação do Observer completa: PadraoObserverImpl_1.zip
Download de uma implementação do Observer com uso das classes da API java.util.Observable e java.util.Observer : PadraoObserverImpl_2.zip

Para exemplificar o uso do padrão de projeto Observer definimos uma aplicação que vamos chamar de “Bolsa de Valores”. Essa aplicação obtém o índice da bolsa de valores e exibe em formato texto ou em um gráfico. (Exemplo completo disponível no artigo download)

Download da implementação do Observer aplicado ao exemplo da Bolsa de Valores: PadroObserverBolsa.zip




Considerações:

O padrão atende as expectativas reduzindo bastante o acoplamento entre as abstrações. No entanto, em java, quando o ConcreteSubject precisa estender a classe Subject não pode estender de outra classe dificultando sua reutilização.

Na solução do padrão Observer apresentada existe apenas um método de atualização onde devemos passar o Subject ou o estado do Subject. Isso torna a missão de descobrir quem disparou a mudança no estado uma tarefa árdua (Sauvé, J., 2006).

A solução de proposta utilizando o Listner (equivalente ao Observer) é implementa pelo Java Swing. Permite a criação de vários eventos que são disparados executando os métodos associados. Ela também facilita a descoberta da fonte do evento. Conseguimos obter um código mais claro e os observares são registrados de forma mais específicada (Sauvé, J., 2006).

As duas implementações do padrão Observer citadas tem problemas pois tanto o ConcreteSubject quanto o ConcreteObserver não estão apenas com seus métodos de “negócio”. É necessário inserir código para tratar o problema da notificação dos observadores não sendo possível a reutilização direta desses objetos.

Espero ter contribuído para seus estudos sobre padrões de projeto.

9 comentários:

  1. Acho interessante esse padrão de projeto embutido na linguagem, mas às vezes o Java peca pela "verbosidade" e complexidade. Vejam o mesmo padrão embutido na tookit Qt(C++), utilizando o conceito de sinais e slots:

    //Declaração da classe Counter:

    class Counter : public QObject
    {
    ...

    public slots:
    void setValue(int value);

    signals:
    void valueChanged(int newValue);

    private:
    int m_value;
    };

    Counter a, b;

    //sinal emitido por a conectado ao slot de b
    QObject::connect(&a, SIGNAL(valueChanged(int)),&b, SLOT(setValue(int)));

    //Emissão do sinal:

    void Counter::setValue(int value)
    {
    if (value != m_value) {
    m_value = value;

    emit valueChanged(value);

    }
    }
    Não vou explicar esse código. Tirem suas próprias conclusões.

    ResponderExcluir
  2. A linguagem java tem como uma de suas características sua "pureza". Java prefere não alterar a sintaxe ou criar artifícios na linguagem para fazer as coisas. As anotações penaram para entrar na API.

    A "verbosidade" permite em certo ponto que uma pessoas que conheça a linguagem entenda o que esta acontecendo.

    Sabemos que alterar a API para fazer isso não é uma tarefa difícil.

    Para ficar menos código podemos utilizar aspectos. (Próximo Post)

    E fica um desafio um post com uma implementação do Observer usando Anotações. :)
    []'s

    ResponderExcluir
  3. Para tornar o código mais simples é preciso criar uma API menos abstrata. Um bom exemplo é a classe Console do Java 6. Agora você tem comandos como "Console.printf", "Console.readLine" e "Console.readPassword". Antigamente era uma tonelada de código pra fazer a mesma coisa. É só ter boa vontade e bom senso que a coisa anda :D

    ResponderExcluir
  4. Seu exemplo foi perfeito.
    É exatamente como trabalha o Java, simplificando a API mas sem alterar aspectos da estrutura da linguagem. Isso contribui para manter a compatibilidade e a expressividade.

    O importante é que concordamos.

    Só o bom senso vai fazer a coisa andar.

    ResponderExcluir
  5. Muito bom o post, achei que estava faltando mesmo falarmos de padroes de projeto.

    quanto ao seu desafio, dando uma googleada achei esse site

    http://code.google.com/p/aoplib4j/wiki/ObserverPatternHowTo

    serve ?


    rsrsrs

    ResponderExcluir
  6. O site é legal mais ele esta usando aspectos e anotações. No próximo post vou colocar uma solução usando apenas aspectos.

    E o desafio continua alguem pode postar uma solução apenas com anotações.

    :)

    Voce pode postar suas impressões sobre essa solução que voce encontrou.

    ResponderExcluir
  7. Mário cheque os links das implementações do padrão, eles estão fora.
    E complementando, também gostei muito do post, que venham mais posts sobre padrões de projeto, inclusive postados por mim.. Estou pensando em colocar alguns depois.. :)

    ResponderExcluir
  8. Valeu Marcelo links corrigidos.

    Estamos aguardando suas contribuições.

    ResponderExcluir