Artigo no estilo Mentoring
Mentoring:Padrões de projeto são soluções prontas e reutilizáveis para problemas recorrentes da orientação a objetos, entre eles os principais são: forte acoplamento entre classes, dificuldade de reutilização de componentes, falta de modularização, duplicação de código e altos custos com manutenção. Os padrões de projeto são apresentados no livro “Design Patterns: Elements of Reusable Object-Oriented Software”, dos autores E. Gamma, R. Helm, R. Johnson e J. Vlissides, mais conhecidos como Padrões GoF (Gang of Four), ver referências bibliográficas na sessão Links. No artigo da edição 152 da Revista ClubeDelphi foram abordados os padrões da categoria criacionais, incluindo Abstract Factory, Factory Method, Singleton e Builder, que tinham por finalidade resolver problemas com forte acoplamento de classes devido a criação de objetos concretos. Neste artigo, vamos abordar alguns padrões do grupo Estrutural, que têm por finalidade mostrar como formar objetos a partir de funcionalidades de outros objetos, seja por herança de abstrações, associações e composição. Os padrões apresentados neste artigo são o Adapter, Bridge, Composite, Decorator e Façade.

Em que situação o tema é útil
Padrões de projeto estruturais são úteis para criar softwares mais fáceis de serem mantidos, evoluídos, promovendo reutilização de código, uso de boas práticas de programação orientada a objetos, redução de custos com manutenção, já que permitem que alterações em um determinado sistema não quebrem outras funcionalidades, reduzindo a dependência entre classes, através do uso exaustivo de abstrações. Dos padrões tratados neste artigo, o Adapter serve para permitir a comunicação entre duas classes com interfaces distintas; Bridge serve para separar totalmente a interface de um objeto de sua implementação concreta; Composite permite criar composições de objetos; Decorator permite adicionar funcionalidades a um objeto sem usar herança estática, usando herança de “caixa-preta”, através da implementação por delegação; Façade ajuda a tornar um subsistema de classes mais fácil de utilizar. Como na edição anterior, primeiramente será apresentada uma descrição formal de cada padrão segundo GoF, depois um exemplo prático em Delphi.

Adapter

A intenção do padrão Adapter, também conhecido como Wrapper, é converter a interface de uma classe em outra interface esperada pelos clientes. Permite que classes trabalhem em conjunto, pois de outra forma não poderiam, devido ao fato de terem interfaces incompatíveis. O padrão pode ser usado quando se quiser usar uma classe existente, mas sua interface não corresponder à interface que necessita; ou quando quiser criar uma classe reutilizável que coopere com classes não relacionadas ou não previstas, ou seja, classes que não necessariamente tenham interfaces compatíveis; você precisa usar várias subclasses existentes, porém, quando for impraticável adaptar essas interfaces criando subclasses para cada uma. O padrão traz alguns benefícios. Um adaptador de classe adapta Adaptee a Target através do uso efetivo de uma classe Adapter concreta, com isso, permite a Adapter substituir algum comportamento do Adaptee, uma vez que Adapter é uma subclasse de Adaptee. Um adaptador de objeto permite que um único Adapter trabalhe com muitos Adaptees. O Adapter também pode acrescentar funcionalidades a todos os Adaptees de uma só vez.

Os participantes do padrão de projeto são:

· Target – define a interface específica do domínio que o Client usa;

· Client – colabora com objetos compatíveis com a interface de Target;

· Adaptee – define uma interface existente que necessita ser adaptada;

· Adapter – adapta a interface do Adaptee à interface do Target;

Para entender melhor o padrão Adapter, vamos recorrer a alguns objetos do mundo real. Por exemplo, digamos que quiséssemos conectar nosso notebook em uma tomada para recarregar sua bateria. Ao entrar em uma sala e encontrar um ponto livre, reparamos que a tomada fêmea segue o novo padrão brasileiro NBR 14136, enquanto nosso notebook tem um cabo com plug macho no padrão norte americano NEMA 5. Ou seja, estamos com problemas para conectar dois objetos, pois eles possuem interfaces incompatíveis. A solução para este problema no mundo real é fácil de ser resolvida, precisamos de um Adaptador, ou Adapter. Ele vai se encarregar de converter o a interface do Adaptee (o plug do nosso notebook) em um formato que o Target entenda (o alvo, a tomada, onde realmente queremos conectar). A Figura 1 mostra um exemplo de como seriam nossos personagens do padrão de projeto em objetos do mundo real.

img

Figura 1. Adaptador no mundo real conecta duas interfaces distintas

No mundo orientado a objetos, um Adapter é frequentemente encontrado em muitas situações. No Delphi, por exemplo, temos dezenas de aplicações deste padrão. Vamos observar a arquitetura do novo DataSnap. No modelo antigo do DataSnap (e primeiras versões do MIDAS), tínhamos um componente de conexão remoto para cada tipo de protocolo que nosso servidor de aplicação pudesse trabalhar. Por exemplo, um DCOMConnection era utilizado no cliente para conectar a um servidor DCOM, MTS ou COM+. A partir do Delphi 6, com o suporte a Web Services, foi possível utilizar um SOAPConnection para conectar em um servidor de aplicação baseado em SOAP (Simple Object Access Protocol). E poderíamos citar outros tipos de conexão, como CorbaConnection, WebConnection, SocketConnection e etc. Um ClientDataSet pode então se conectar a qualquer um desses componentes concretos para obter dados de diferentes tipos de servidores, independente do protocolo que usem. Para isso, basta aponta-los para a propriedade RemoteServer de ClientDataSet (Figura 2), que é do tipo TCustomRemoteServer, classe base para todos os componentes de conexão (SOAPConnection, DCOMConnection, SocketConnection, WebConnection, CorbaConnection etc.). Com o novo DataSnap, do Delphi 2009 em diante, uma grande mudança foi feita, ao invés de termos um componente com uma implementação concreta para cada protocolo de comunicação DataSnap, passamos a usar um único componente de conexão, o próprio SQLConnection do DBExpress. O código de acesso dependente de protocolo passou a residir então em um driver do DBExpress (DLL). Agora vem o problema, se tentarmos conectar um ClientDataSet em um SQLConnection pela propriedade RemoteServer, o que acontece? O SQLConnection nem aparece na lista, pois este descende de TCustomConnection, e não de TCustomRemoteServer. Como é impossível usar herança múltipla no Delphi, pelo menos de forma estática, não há uma forma de resolver o problema sem causar uma mudança profunda na VCL, modificar a classe base de um dos tipos citados, o que iria ferir princípios fundamentais da orientação a objetos (e uma reação em cadeia de alterações em todo framework). Então, um padrão de projeto foi aplicado para resolver o problema de forma elegante. A classe TDSProviderConnection funciona como uma “ponte” entre um ClientDataSet e um SQLConnection, fazendo com que o SQLConnection “finja” ser um RemoteServer para o ClientDataSet ( ...

Quer ler esse conteúdo completo? Tenha acesso completo