O design pattern Chain of Responsibility, o Servlet Filter e as Exceptions em Java

Padrões de projeto

Alguma vez você já passou pela situação de entrar em uma sala de aula e não ter uma cadeira para sentar? Pois quando aconteceu comigo, eu pedi para o professor que me conseguisse uma e o que aconteceu? Aconteceu que o professor não sabia onde encontra-la e, prontamente, solicitou-a ao inspetor. Para o meu azar, o inspetor não encontrou cadeiras extras no depósito de materiais o que o obrigou a solicitar novas cadeiras ao diretor que poderia adquirir novas cadeiras na loja de material escolar. No outro dia, assim que o diretor estava de posse da nova cadeira, ele entregou-a ao inspetor, que entregou ao professor que sinalizou-a para mim assim que adentrei a sala! O professor então começou a ensinar o design pattern comportamental “Chain of responsibility”

O design pattern Chain of Responsibility trata exatamente da limitação com que alguém (um objeto) pode lidar com um determinado pedido. Se o alguém não pode lidar com aquela situação, então ele passa a solicitação (delega) para uma outra que pode ou não ter os recursosconhecimentos e permissões necessárias para atende-la gerando assim uma cadeia recursiva de pedidos.

Em outras palavras, ele permite ao objeto não precisar conhecer todos os outros objetos que poderiam atender a todas a uma requisição especifica o que desacopla os objetos e, como os “handlers” envolvidos estão conectados de forma simples, torna-se flexível.

“Em projetos orientados a objetos manter os objetos com acoplamento fraco, mantendo específica e mínima a responsabilidade entre eles, faz com que mudanças sejam inseridas com menos risco de falhas. Os clientes apenas enxergam a interface visível do objeto permanecerem isolados de detalhes de implementação [Metsker, 2004]”.

Agora você pode estar se perguntando? Ok, esse padrão parece interessante, mas o que ele tem de relação aos filtros ou as exceções disparadas em Java ?

O Servlet Filter do Java é considerado uma das mais populares variações de implementação de CoR porque o seu método chain.doFilter() é aquele a ser invocada para gerar a cadeia de pedidos assim como a forma com que as exceções são tratadas nessa linguagem já que, quando ocorre,  a excessão vai recursivamente escalar a pilha de métodos até encontrar uma classe capaz de trata-la, senão, o próprio handler irá trata-la!
Mãos à massa ! Como poderiamos utilizar esse pattern de uma forma didática a partir do exemplo da escola?

Podemos começar criando os possíveis pedidos que podem ocorrer no ambiente escolar.

RequisicaoEscolar.java

public enum RequisicaoEscolar {
	AQUISICAO_DE_CADEIRA,
	DUVIDA_SOBRE_A_REVOLUCAO_FRANCESA,
	DUVIDA_SOBRE_VANGUARDAS_LITERARIAS,
	INFORMACAO_DE_NUMERO_DE_SALA
}

Podemos agora modelar a classe responsável por encadear um objeto em outro.

Responsavel.java

public abstract class Responsavel {

    protected Responsavel sucessor;

    public void setSucessor(final Responsavel sucessor){
	this.sucessor = sucessor;
    }

    public abstract void atende(final RequisicaoEscolar requisicao);

}

Modelamos as ações da pessoas envolvidas, por exemplo um professor de Literatura.

ProfessorDeLiteratura.java

public class ProfessorDeLiteratura extends Responsavel {
    @Override
    public void atende(final RequisicaoEscolar requisicao) {
        if (requisicao.equals(RequisicaoEscolar.DUVIDA_SOBRE_VANGUARDAS_LITERARIAS)){
            System.out.println(“O professor de Literatura respondeu a dúvida!”);
        } else {
            if (sucessor != null) {
                System.out.println(“O professor de literatura não pode atender uma “ + requisicao.toString() + “, pediu para outra pessoa responder”);
                sucessor.atende(requisicao);
            }
        }
    }
}

Modelamos as ações, por exemplo um professor de História.

ProfessorDeHistoria.java

public class ProfessorDeHistoria extends Responsavel {
    @Override
    public void atende(final RequisicaoEscolar requisicao) {
        if (requisicao.equals(RequisicaoEscolar.DUVIDA_SOBRE_A_REVOLUCAO_FRANCESA)){
            System.out.println(“O professor de história respondeu a dúvida sobre a revolução francesa!”);
        } else {
            if (sucessor != null) {
                System.out.println(“O professor de história não pode atender uma “ + requisicao.toString() + “, pediu para outra pessoa responder”);
                sucessor.atende(requisicao);
            }
        }
    }
}

Modelamos as ações do inspetor.

Inspetor.java

public class Inspetor extends Responsavel {
    @Override
    public void atende(final RequisicaoEscolar requisicao) {
        if (requisicao.equals(RequisicaoEscolar.INFORMACAO_DE_NUMERO_DE_SALA)){
            System.out.println(“O inspetor informou que a sala de história fica no 2º andar!”);
        } else {
            if (sucessor != null) {
                System.out.println(“O inspetor não pode atender uma “ + requisicao.toString() + “, pediu                                                               para outra pessoa atender”);
                sucessor.atende(requisicao);
            }
        }
    }
}

Modelamos as ações do Diretor.

Diretor.java

public class Diretor extends Responsavel {
    @Override
    public void atende(final RequisicaoEscolar requisicao) {
        if (requisicao.equals(RequisicaoEscolar.AQUISICAO_DE_CADEIRA)){
            System.out.println(“O diretor comprou uma cadera nova!”);
        } else {
            if (sucessor != null) {
                System.out.println(“O diretor de história não pode atender uma “ + requisicao.toString() + “, procurou outra pessoa para atender”);
                sucessor.atende(requisicao);
            }
        }
    }
}

E finalmente, agora podemos testar a criação!

SimulacaoDoUsoDoChainOfResponsibility.java

public class SimulacaoDoUsoDoChainOfResponsibility {

    public static void main(final String[] args) {
        Responsavel professorDeHistoria = new ProfessorDeHistoria();
        Responsavel professorDeLiteratura = new ProfessorDeLiteratura();
        Responsavel inspetor = new Inspetor();
        Responsavel diretor = new Diretor();

        professorDeHistoria.setSucessor(professorDeLiteratura);
        professorDeLiteratura.setSucessor(inspetor);
        inspetor.setSucessor(diretor);

        professorDeHistoria.atende(RequisicaoEscolar.AQUISICAO_DE_CADEIRA);
        professorDeHistoria.atende(RequisicaoEscolar.DUVIDA_SOBRE_A_REVOLUCAO_FRANCESA);
        professorDeHistoria.atende(RequisicaoEscolar.INFORMACAO_DE_NUMERO_DE_SALA);
        professorDeHistoria.atende(RequisicaoEscolar.DUVIDA_SOBRE_VANGUARDAS_LITERARIAS);
    }
}

Então a saída esperada no console será:

O professor de história não pode atender uma AQUISICAO_DE_CADEIRA pediu para outra pessoa responder
O professor de literatura não pode atender uma AQUISICAO_DE_CADEIRA pediu para outra pessoa responder
O inspetor não pode atender uma AQUISICAO_DE_CADEIRA pediu para outra pessoa atender
O diretor comprou uma cadeira nova!
O professor de história respondeu a dúvida sobre a revolução francesa!
O professor de história não pode atender uma INFORMACAO_DE_NUMERO_DE_SALA, pediu para outra pessoa responder
O professor de literatura não pode atender uma INFORMACAO_DE_NUMERO_DE_SALA, pediu para outra pessoa responder
O inspetor informa que a sala de história fica no 2º andar!
O professor de história não pode atender uma DUVIDA_SOBRE_VANGUARDAS_LITERARIAS, pediu para outra pessoa responder
O professor de literatura respondeu a dúvida sobre vanguardas literárias!

Resumindo

Quais as vantagens do CoR ? 

1. Evita acoplamento do transmissor de um requisição com seus receptores, fazendo com que mais de um projeto tenha a chance de manipular a requisição.
2. Encadeia os objetos receptores e passa a requisição ao longo dessa cadeia até que um objeto possa manipulá-lo.
3. Reduz a vinculação.
4. Adiciona flexibilidade.
5. Permite que um conjunto de classses atue como uma classe; eventos produzidos em uma classe podem ser enviados para outras classes dentro da composição.

Quando usar esse design pattern ?

1. Quando você tem mais de um “handler” por requisição
2. Quando você possui “handlers” que deveriam delegar pedidos para outros “handlers”;
3. Conjunto de “handlers” que variam dinamicamente.

 

E se você gostou desse artigo, você também poderá gostar deste:
Explorando os benefícios do uso do Design Pattern Bridge 

Referências
http://www.codeproject.com/KB/architecture/chain_response.aspx
http://www.avajava.com/tutorials/lessons/chain-of-responsibility-pattern.html?page=1
http://www.pg.cefetpr.br/coinf/simone/patterns/chain.php
http://www.vincehuston.org/dp/chain.html
http://imasters.com.br/artigo/17645/php/design_patterns_e_o_desenvolvimento_em_php_chain_of_responsibility/
http://c2.com/cgi/wiki?ChainOfResponsibilityPattern

Anúncios