sexta-feira, 26 de novembro de 2010

Padrão de Projeto "Chain of Responsibility"

Imagine a situação em que uma grande empresa possui uma ampla rede de representação de seus produtos constituída, basicamente, por escritórios de venda espalhados em diversas cidades. Cada escritório possui um conjunto de vendedores que vão até os varejistas oferecer os produtos da empresa. Varejistas podem estar em áreas populosas, como supermercados, ou em áreas remotas, como os comércios que abastecem bairros rurais. Ao chegar no varejista, o vendedor utiliza um sistema fornecido pela empresa para registrar os pedidos de produtos.

Na situação descrita, o objetivo é registrar os pedidos na base de dados da central de distribuição da empresa. Porém, por problemas de comunicação com a central, o computador portátil do varejista pode não conseguir conectar com a base central para registrar os pedidos. Quando isso ocorrer, o sistema deve tentar salvá-los na base de dados do escritório. Quando a base do escritório também não estiver acessível, os pedidos deverão ser salvos na base de dados local, no próprio computador portátil do vendedor. Futuramente, de alguma forma fora do escopo de nossa discussão, todos os dados poderão ser carregados na base central.

Várias soluções podem ser dadas para o problema acima, entre elas a descrita no padrão de projeto Chain of Responsibility. Antes de resolver o problema utilizando o padrão de projeto, apresentarei a estrutura do padrão e explicarei seu funcionamento.


O diagrama acima apresenta uma classe abstrata chamada Responsabilidade que possui uma operação responsável por executar algum serviço. Podemos notar pela nota ancorada à classe que a opereção é bastante simples: se existir um sucessor, chama a mesma operação no sucessor, senão, gera um erro informando que a operação não pode ser executada. Notem que o sucessor é uma referência para a própria classe Responsabilidade. Através dessa auto-referência, é possível montar uma cadeia de instâncias da classe responsabilidade, como em uma lista encadeada. Obviamente, a classe Responsabilidade não pode ser instanciada diretamente, pois é uma classe abstrata. Para instanciá-la e, assim, montar a cadeia, é necessário especializá-la em classes concretas, representadas no diagrama como as classes ResponsabilidadeConcreta1 e ResponsabilidadeConcreta2.

As classes concretas que especializam a Responsabilidade definirão as possíveis implementações do serviço. Conforme podemos observar na nota, elas se comportam da seguinte forma: se for possível executar o serviço por aquela classe, executa-o, senão, chama a operação de mesmo nome na classe geral (Responsabilidade). Como já foi explicado, a classe geral, basicamente, chama a mesma operação no sucessor, que pode ser instância de uma outra classe concreta. Com isso, a operação é sempre repassada até chegar em uma instância que possa realmente executar o serviço ou até não haver mais sucessor.

Voltando ao problema do início do post, fica fácil perceber que o padrão se encaixa ao problema descrito. No diagrama de classes criaremos a classe abstrata PedidoDAO e as classes concretas, que representam os nós da cadeia, serão PedidoDAOCentral, PedidoDAOEscritorio e PedidoDAOLocal. A primeira será responsável por salvar o pedido na central, a segunda por salvar no escritório e a última por salvar na base de dados local do computador portátil do vendedor. Segue o diagrama de classes correspondente:


Ainda será necessário montar a cadeia na ordem correta. O GoF não descreve no padrão a responsabilidade de montar a cadeia na ordem correta. Porém, podemos fazer uma alteração no diagrama para incluir a classe DAOBuilder, que possui a operação responsável por construir a cadeia de responsabilidades.


Segue, abaixo, o código Java da classe DAOBuilder:

public class DAOBuilder {
 public static PedidoDAO buildPedidoDAO() {
  PedidoDAOCentral central = new PedidoDAOCentral();
  PedidoDAOEscritorio escritorio = new PedidoDAOEscritorio();
  PedidoDAOLocal local = new PedidoDAOLocal();
  central.setSucessor(escritorio);
  escritorio.setSucessor(local);
  return central;
 }
}

Assim, quem for utilizar a cadeia precisará conhecer apenas as classes DAOBuilder e PedidoDAO. Veja abaixo um exemplo de código de utilização em linguagem Java:

Pedido pedido = new Pedido();
// TODO: configura os dados do pedido.
PedidoDAO dao = DAOBuilder.buildPedidoDAO();
dao.inserirPedido(pedido);

Mais informações podem ser encontradas no livro "Design Patterns: Elements of Reusable Object-Oriented Software", de Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides. Devido ao número de autores, o livro é também conhecido como GoF (Gang of Four - Gangue dos Quatro).

Nenhum comentário:

Postar um comentário