Explorando os benefícios do uso do Design Pattern Bridge

Alguns artigos atrás, tive a oportunidade de explicar brevemente algumas das principais características que levaram o design pattern Chain of responsibility a ser relacionado com o modo de tratamento de exceções em Java e a tornar-se uma implementação concreta de um Servlet Filter. Neste presente artigo, tenho a intenção de demonstrar a importância do conhecimento e aplicação de mais um padrão GoF clássico, o design pattern Bridge.

O padrão Bridge é mais um dos vinte e três padrões descritos no livro “Design Patterns: Elements of Reusable Object-Oriented Software e é muito utilizado quando se deseja separar abstração de implementação justamente porque lida diretamente com a estrutura com que as interfaces e classes são elaboradas. Essa característica peculiar  o elevou a ser considerado como um padrão estrutural e tornou possível sua aplicação em pontes de conexão com Banco de Dados JDBC, implementações de desenho gráfico em diferentes plataformas, Java Swing, Java AWT e até como parte da implementação de listas em Java.

As características que tornam o padrão Bridge interessante envolvem: a capacidade de evitar uma ligação permanente entre uma abstração e a implementação, a propriedade de permitir a extensão de uma abstração, a proteção dos clientes com relação as alterações de implementação, a capacidade de esconder completamente a implementação do cliente, melhoria na gestão de um conjunto grande de hierarquias e extensões de uma abstração. A capacidade de evitar uma ligação permanente entre abstração e implementação pode ser útil quando por exemplo desejamos alterar a implementação das aparências de uma janela em tempo de execução como é usado no Windows ou nos componentes Swing e AWT do Java. A propriedade de permitir extensão de uma abstração pode ser útil quando é previsto a possibilidade de diferentes implementações ou mesmo novas implementações para essa mesma abstração o que permite flexibilidade para projetos futuros. A capacidade de esconder uma implementação completamente pode ser útil em linguagens como o C++ que permite que que a classe esteja inadvertidamente a disposição do cliente. O padrão Bridge também garante a proteção dos clientes contra alteração de implementações porque permite retrocompatibilidade, ou seja, por exemplo no desenvolvimento de uma biblioteca de classes na qual as novas classes conseguem trabalhar com código já existente das classes já desenvolvidas. A capacidade de gestão de um conjunto grande de hierarquias e extensões de uma abstração é explicada pelo fato de que pode acontecer casos em que uma abstração tenha muitas extensões e hierarquia mas, esse padrão ao separar as possíveis implementações, permite uma hierarquia de chamadas mais generalizada.

Agora que temos um melhor entendimento sobre o que é o pattern Bridge, vamos entender melhor sua estrutura partindo de diagrama de classes abaixo:

UML do Design Pattern Bridge

A Abstração nesse modelo nada mais é do que a interface que o cliente usa para interagir com a abstração do mundo real e que é implementada pela Abstração Concreta. Nessa abstração concreta é mantido uma referência a uma interface de um Implementador e é exatamente o que torna possível desacoplar a abstração da implementação porque agora a abstração faz referências a um ou mais métodos da classe implementador. Em outras palavras, toda chamada de operação na abstração é enviada diretamente para a referência do Implementador que poderiam ser o Implementador Concreto A ou o Implementador Concreto B.

Imagine a situação onde temos programadores e homologadores, perceba que ambos são colaboradores de uma empresa e recebem tarefas de acordo com a área em que atuam, suponha também que a depender de fatores externos possam vir a receber tarefas diferenciadas. Por exemplo, um programador pode criar rotinas em Java ou Ruby e se estiver com poucos projetos pode criar testes automatizados ou manuais. Um Homologador geralmente cria testes manuais ou automatizados mas em um mundo caótico pode vir a criar rotinas Java ou Ruby.

Podemos imaginar então que a abstração seja o trabalhador,

public interface Colaborador {

	void produz();

	void recebeTarefa(Tarefa tarefa);

}

E temos duas realizações desse colaborador que são o Programador,

public class Programador implements Colaborador {

	private Tarefa tarefa;

	public Programador(final Tarefa tarefa) {
		this.tarefa = tarefa;
	}

	@Override
	public void produz() {
		System.out.println("nProgramador trabalhando ");
		tarefa.realiza();
	}

	@Override
	public void recebeTarefa(final Tarefa tarefa) {
		this.tarefa = tarefa;
	}

}

e a abstração Homologador.

public class Homologador implements Colaborador {

	private Tarefa tarefa;

	public Homologador(final Tarefa tarefa) {
		this.tarefa = tarefa;
	}

	@Override
	public void produz() {
		System.out.println("nHomologador trabalhando ");
		tarefa.realiza();
	}

	@Override
	public void recebeTarefa(final Tarefa tarefa) {
		this.tarefa = tarefa;
	}

}

Agora podemos entender o implementador como a Tarefa que um colaborador realiza:

public interface Tarefa {

	void realiza();

}

Podemos ter a tarefa de programação Java

public class ProgramacaoJava implements Tarefa {

	@Override
	public void realiza() {
		System.out.println("cria muitas linhas de código Java");
	}

}

Podemos ter a tarefa de programação Ruby

public class ProgramacaoRuby implements Tarefa {

	@Override
	public void realiza() {
		System.out.println("cria muitas linhas de código Ruby");
	}

}

Podemos ter a tarefa de criação de testes automatizados

public class TestesAutomatizados implements Tarefa {

	@Override
	public void realiza() {
		System.out.println("constrói testes automatizados");
	}

}

Podemos ter a tarefa de criação de testes manuais

public class TestesManuais implements Tarefa {

	@Override
	public void realiza() {
		System.out.println("constrói testes manuais");
	}

}

E agora que temos abstrações e os implementadores desenvolvidos vamos finalmente testar esse Pattern na prática !

public class ExemploDoPatternBridge {

	public static void main(final String[] args) {

		// Eu gosto de programar em java, então eu posso criar um programador que executa a tarefa de programar em Java
		Tarefa tarefaDoProgramador = new ProgramacaoJava();
		final Colaborador programador = new Programador(tarefaDoProgramador);
		programador.produz();

		// Eu também gosto de Ruby então poderia desenvolver em Ruby!
		tarefaDoProgramador = new ProgramacaoRuby();
		programador.recebeTarefa(tarefaDoProgramador);
		programador.produz();

		// Mas se a situação aperta e me pedem testes automatizados, não tem problema eu posso fazer também!
		tarefaDoProgramador = new TestesAutomatizados();
		programador.recebeTarefa(tarefaDoProgramador);
		programador.produz();

		// No caso do colaborador, temos o mesmo, ele faz testes manuais
		Tarefa tarefaDoHomologador = new TestesManuais();
		final Colaborador homologador = new Homologador(tarefaDoHomologador);
		homologador.produz();

		// Mas se a situação aperta ele pode programar até em Ruby!
		tarefaDoHomologador = new ProgramacaoRuby();
		homologador.recebeTarefa(tarefaDoHomologador);
		homologador.produz();

	}

}

Para concluir, se você sentiu uma semelhança com um outro padrão, muito cuidado! É muito comum a confusão entre os patterns Bridge Adapter ou Bridge e Strategy ! Tenha sempre em mente que o Bridge tem a intenção de separar a abstração da implementação, ou seja, será utilizado quando temos uma interface que varie muito de implementação. O padrão Adapter existe para sanar a incompatibilidade de classes que fazem trabalhos semelhantes em uma interface única e o padrão Strategy se preocupa em desacoplar comportamento e não a abstração.

Download do código fonte pelo Git:
git://github.com/fpierin/java_bridge_pattern.git

E se você gostou desse artigo, talvez você goste desse também:
O design pattern Chain of Responsibility, o Servlet Filter e as Exceptions em Java

Referências:
http://www.go4expert.com/forums/showthread.php?t=5127
http://www.cs.clemson.edu/~malloy/courses/patterns/bridge.html
http://c2.com/cgi/wiki?BridgePattern
http://c2.com/cgi/wiki?GangOfFour
http://delphipatterns.blog.com/2011/02/22/bridge/
http://www.java2s.com/Code/Java/Design-Pattern/BridgePatterninJava3.htm
http://weblogs.asp.net/mnolton/archive/2004/02/02/66471.aspx
http://howtoportal.appspot.com/technical/patterns/Howtoportal-technical-page-java-design-pattern-with-Example-Creational-Behavioral-Structural.jsp#_Toc233610502
http://www.roseindia.net/designpattern/bridge-pattern.shtml
http://www.50minutos.com.br/blog/post/Um-pattern-em-C-por-dia-Bridge-pattern-estrutural.aspx
http://cesarioramos.wordpress.com/2010/01/05/the-beautifull-bridge-pattern/

Anúncios