Design Patterns

Autor: Marcelo Luiz Hümmelgen – GPS   

1. Introdução

Nos últimos anos verificou-se o grande aumento da utilização da tecnologia de orientação a objetos. Desde o início da década de 90 tem-se acompanhado, a princípio na comunidade acadêmica e após nas empresas, a crescente adoção da Orientação a Objetos para o desenvolvimento de aplicativos. Este aumento deve-se, principalmente, às soluções propostas por esta tecnologia, as quais vêm a amenizar os efeitos dos problemas gerados pela Crise de Software. No começo, algumas empresas viam com ressalvas os benefícios trazidos pela orientação a objetos, devido à pouca produtividade inicial conseguida por seus desenvolvedores; entretanto, passados agora alguns anos, não existem mais dúvidas quanto à sua adoção, sendo apenas uma questão de tempo para sua completa utilização de seus princípios.

Como conseqüência da adoção da metodologia Orientada a Objetos para desenvolvimento de aplicativos, tivemos uma explosão de métodos, linguagens e ferramentas que implementam, de uma forma ou outra, todos os conceitos apresentados por esta tecnologia. Hoje existe uma tentativa de se padronizar uma linguagem para especificação de sistemas orientados a objetos, a UML. Esta linguagem é baseada em um conjunto de métodos já utilizados e adotados em diversos lugares do mundo, os quais são OMT e Booch. No campo das linguagens de programação, também temos uma série delas, cada qual mais apropriada para um objetivo; só para citar alguns casos, temos C++, SmallTalk, e mais recentemente Java.

Uma vez que a Orientação o Objetos é uma realidade, e métodos e linguagens são abundantes no mercado, a discussão volta-se agora para outra direção. A simples adoção dos conceitos não é o suficiente, para a construção de aplicativos com qualidade, mesmo que acompanhados das melhores ferramentas. Incluam-se aí as linguagens de programação. A discussão agora é como projetar, mas como projetar da melhor maneira possível.

1.1 Desenvolvimento Orientado a Objetos.

Desenvolver software orientado a objetos é difícil, por mais que todos digam que é fácil, não é. É difícil, ainda mais quando o desenvolvedor vem com uma bagagem de desenvolvimento semi-estruturado e estruturado. Agora, desenvolver software orientado a objetos e que seja reusável é infinitamente mais difícil.

Talvez, num futuro não muito distante, venham nos perguntar: "Como era possível desenvolver aplicativos sem utilizar objetos ?"; da mesma maneira que hoje perguntamos: "Como era possível desenvolver software de maneira não estruturada ?".

É claro que o primeiro projeto é sempre o mais crítico, já que existe a necessidade de se desenvolver tudo, a partir do nada. No segundo, alguns objetos que foram pensados para o primeiro podem ser utilizados, com algumas adequações. No terceiro, podem ser utilizados objetos do primeiro e do segundo; assim, conforme vamos desenvolvendo mais projetos Orientados a Objetos mais fácil para os desenvolvedores vai se tornando, uma vez que muito do que foi elaborado anteriormente pode ser utilizado para desenvolvimentos futuros. Em conseqüência da reutilização de código, os projetos, em si, vão ficando melhores e mais bem acabados, uma vez que os objetos neles utilizados já são completamente funcionais.

Isto deve-se porque, normalmente, todos os projetos envolvem a resolução de problemas recorrentes; e quantas vezes não nos pegamos com a sensação de já termos resolvido um problema semelhante em algum momento do passado. Este conhecimento, de como se resolver um determinado problema, acumulado durante os anos, é o que chamamos de experiência, e esta experiência está ligada diretamente aos responsáveis pela resolução carregada apenas pelos desenvolvedores que um dia resolveram aquele problema. Mas como podemos armazenar esta experiência para outros usos, ou então para o auxílio de outros desenvolvedores.

Este ponto é importante, um desenvolvedor experiente nunca começa a desenvolver um sistema realmente do zero. Ele aproveita desenvolvimentos anteriores que deram certo e que foram sendo refinados com o tempo, como ponto de partida para um novo sistema.

Se pudéssemos catalogar esta experiência anterior em uma forma que qualquer pessoa, seja experiente ou não, conseguisse realmente utilizar para resolver seus problemas de desenvolvimento, conseguiríamos um grande aumento na qualidade dos projetos e uma redução sistemática nos tempos de desenvolvimento dos sistemas.

Um dos principais motivos levantados para a catalogação da experiência é fazer com que desenvolvedores novatos possam agir como se fossem desenvolvedores especialistas, sem a necessidade de passar anos ganhando experiência.

1.2 Histórico

No final da década de 70, Christopher Alexander, passava por um problema semelhante, só que relacionado à arquitetura e à engenharia civil, percebendo que todas as construções de edifícios, os quais eram funcionais e confortáveis, possuíam algumas características em comum, resolveu catalogar estas soluções em seu livro The Timeless Way of Building.

Durante anos, os especialistas na área de engenharia de software tentaram adequar as idéias de Alexander para a construção de sistemas de informação. Finalmente, em 1994, liderados por Erich Gamma a GoF (Gang of Four) - Erich Gamma, Richard Helm, Ralph Johnson a John Vlissides publicaram o livro que deu origem à onda dos Patterns na área de informática, Design Patterns: Elements of Reusable Object-Oriented Software. O primeiro catálogo bem descrito sobre patterns de projeto para programas orientados a objeto. Após isto, seguiram outros livros de outros autores, publicações, papers, conferências, entre outros.


2. Conhecendo Patterns

2.1 O que são

Segundo Christopher Alexander, "Cada Pattern descreve um problema o qual ocorre repetidamente em nosso ambiente, e então descreve um conjunto de soluções para este problema, de maneira que você possa usar esta solução um milhão de vezes, sem o fazer da mesma maneira duas vezes." [1].

A idéia é capturar experiências comprovadamente corretas em desenvolvimento de software e ajudar a promover a prática de projeto correto. Cada pattern trabalha com um problema específico e recorrente no projeto ou implementação de softwares.

Segundo a "GoF" [4], um pattern, em geral, é formado de quatro elementos essenciais, a saber:

  1. O nome do pattern, uma ou duas palavras utilizadas para descrever o problema, sua solução e conseqüências. Encontrar um bom nome é, normalmente, uma da tarefas mais difíceis e importantes da documentação de um pattern. Ao se designar um bom nome a um pattern, automaticamente aumentamos nosso vocabulário e ele passará a ser adotado pelos nossos colegas de desenvolvimento; assim, quando quisermos expressar uma solução, não há a necessidade de se explicar todo o processo de solução, mas sim apenas citar qual o pattern a ser utilizado;

  2. O problema descreve quando um pattern deve ser aplicado, explicando o problema em si, e o contexto onde é encontrado. Em alguns casos o problema pode conter uma lista de condições, as quais devem ser satisfeitas antes que a utilização do pattern faça sentido;

  3. A solução descreve os elementos que fazem parte do projeto, seus relacionamentos, responsabilidades e colaborações; no entanto, a solução não descreve um projeto completo ou implementação, já que o pattern pode ser utilizado diversas vezes sem que se repita uma mesma implementação. O que deve ser indicado é a idéia da solução do problema;

  4. As conseqüências são os resultados alcançados com a aplicação do pattern. Através delas podem ser verificadas as possibilidades da utilização do pattern para a solução no problema proposto no contexto especificado. Elas podem, inclusive, especificar a linguagem de programação utilizada, bem como peculiaridades ligadas diretamente à implementação. Uma vez que estas conseqüências podem afetar, também, o reuso, devem ser especificados os impactos ocasionados à flexibilidade, à extensibilidade e à portabilidade do sistema.

O ponto de vista de cada indivíduo afeta o que vem a ser ou não um pattern. Não existe uma definição clara em que ponto da abstração deve-se chegar para definição de um pattern. A "GoF" [4] diz que "Patterns não são para projetos como listas linkadas e tabelas Hash, as quais podem ser codificadas como classes e então apenas reusadas para solução de suas necessidades. Nem são complexas a ponto de chegar a projetos para domínios específicos para uma aplicação inteira ou um subsistema. Patterns são a descrição de classes e objetos os quais se comunicam e que são customizados para resolver um problema comum de projeto em um contexto específico"; entretanto, outros autores, como Frank Buschmann e Martin Flower discordam. O primeiro chega a propor categorias para os diversos patterns, as quais cobrem uma série de escalas e abstrações; enquanto o segundo, trabalha sobre uma série de domínios específicos, como os encontrados em seguradoras e corporações financeiras.

2.2 Principais Características

A maior parte dos autores concorda acerca das principais características dos patterns. Muito se pode aprender sobre eles, como funcionam e suas vantagens através de suas características:

  • "Endereçam um problema recorrente em uma situação específica, e apresentam uma solução para isto" [3];

  • "Não são inventados ou criados artificialmente" [4]. São simplesmente soluções que já foram utilizadas em diversos projetos anteriores, e que provavelmente serão utilizados no futuro. Tipicamente, patterns descrevem um conjunto de componentes, classes ou objetos, e suas responsabilidades e relacionamentos;

  • "Nomes de patterns, se escolhidos cuidadosamente, tornam-se parte da linguagem de desenvolvedores" [4]. Eles facilitam a discussão dos problemas e suas soluções, removendo a necessidade de explicação para a solução de um problema particular, desde que todos conheçam a solução daquele pattern e como funciona;

  • "Identificam e especificam abstrações um nível acima de simples classes e instâncias, ou de componentes" [4]. Normalmente patterns descrevem um conjunto de componentes, classes ou objetos, e detalhes de suas responsabilidades e relacionamentos, bem como suas cooperações;

  • "Provêem vocabulário e entendimento comum para os princípios de projeto" [4]. Uma vez que um pattern abstrai uma solução, não existe a necessidade de uma longa e detalhada explicação do problema e o que foi feito para sua solução. Ao citar o nome do pattern utilizado, automaticamente será conhecido o problema, em que contexto se acha e a solução adotada para sua solução; e, ao longo do tempo, estes nomes vão se tornando parte do vocabulário comum de uma equipe de desenvolvimento;

  • "São um meio para documentação de arquiteturas de software" [3]. Através deles pode-se descrever o que se tinha em mente no momento quando se estava projetando um aplicativo. Assim, qualquer um que um dia necessite alterar as estruturas deste sistema terá um conhecimento, não só de como está estruturado, mas também do que levou a ser feito desta maneira, e então prosseguir com o desenvolvimento seguindo estas premissas;

  • "Auxiliam na construção de arquiteturas de software complexos e heterogêneos" [3]. Como cada pattern utiliza um conjunto fechado de classes, regras e relacionamentos, torna-se extremamente mais fácil juntar diversos patterns, os quais se relacionam e colaboram para chegar a um objetivo maior, ou seja, "patterns como blocos de montar através dos quais pode-se construir projetos mais complexos" [4];

  • "Auxiliam no gerenciamento da complexidade do software" [3]. Quando se está desenvolvendo um novo projeto e se faz uso dos patterns, classes, relacionamentos e detalhes ficam escondidos. O que se vê é apenas uma abstração da solução, e como tudo deve funcionar;


2.3 Como descrever

A maneira de se descrever patterns difere de autor para autor; entretanto, a maioria adotou o modelo contexto-problema-solução-conseqüências, adequado de maneira a propiciar uma melhor compreensão das forças que afetam o desenvolvimento de aplicativos orientados a objetos.

Como se viu na PLoP (Pattern Languages of Program Design), não existe modelo único para a descrição de um pattern. Muitos se inspiram no estilo de Christopher Alexander. Outros seguem o modelo apresentado pela "Gang of Four". E outros, ainda, são originais, criando seu próprio meio para descrever suas idéias e soluções para um problema em certo contexto.

Aqui, mostraremos dois dos principais meios adotados para a descrição de uma pattern, a de Erich Gamma [4] e a de Frank Buschmann [3]. Começamos com a turma do "GoF". Segundo Erich Gamma, um pattern pode ser descrito da seguinte maneira:

  • Nome e Classificação do Pattern. Uma ou duas palavras que caracterizem a essência do pattern;

  • Intenção. Uma breve descrição que indique a resposta para algumas perguntas como: O que o pattern faz ? Qual problema ele pretende resolver ?

  • Sinônimos. Caso exista algum outro pattern conhecido que resolva o mesmo problema, deverá ser indicado aqui;

  • Motivação. Um cenário que ilustre o problema e como as classes e objetos utilizados no pattern vêm a resolver este problema;

  • Aplicabilidade. Em qual contexto este pattern pode ser utilizado;

  • Estrutura. Representação gráfica das classes utilizadas no pattern utilizando a notação Object Modeling Technique (OMT) [6];

  • Participantes. Quais as classes que participam da resolução do problema e suas responsabilidades;

  • Colaborações. Como as classes participantes colaboram para executar suas responsabilidades;

  • Conseqüências. Qual o resultado obtido se o pattern for utilizado? Como o pattern suporta o objetivo? Quais os aspectos da estrutura do sistema o deixa variar independente?

  • Implementação. Quais são as dicas e técnicas que devem ser utilizadas no momento da implementação do pattern? Indicar, se houver, restrições quanto à linguagem de programação a ser utilizada;

  • Exemplo do Código. Fragmentos do código que ilustram como pode ser implementado o pattern. Normalmente, são escritos em C++ ou Smalltalk;

  • Usos conhecidos. Sistemas reais onde o pattern pode ser encontrado;

  • Patterns Correlatos. Outros patterns que possuam poucas diferenças em relação a este. Quais as diferenças e onde o outro pattern é mais indicado.

3. Conclusão

Patterns são um novo desenvolvimento na área de engenharia de software. Eles continuarão desenvolvendo modos para ajudar pessoas a aprender sobre patterns e de como usá-los em seus trabalhos.

Para quem está começando agora na utilização de patterns, dois princípios principais devem ser levados em consideração:

  1. Patterns são um ponto de partida onde deve-se procurar soluções para seus problemas. Não são um ponto de destino, ou seja, não se deve desenvolver aplicativos pensando em criar patterns, eles vêm em conseqüência de sua experiência;

  2. Modelos não são certos ou errados, eles são simplesmente mais ou menos úteis;

Existem diversos patterns para desenvolvimento de software orientado a objetos em geral, interface com o usuário, processamento distribuído. Entretanto, outras áreas como: segurança, sistemas de processamento transacional, paralelo, científico e com tolerância a faltas, ainda possuem uma carência muito grande em torno de patterns descritos.

Da mesma forma, existem patterns a mais baixo nível que capturam a experiência em programação; entretanto, hoje eles só são encontrados em C++ e Smalltalk. Patterns descritos para outras linguagens de programação são raros, senão impossíveis de achar. O futuro próximo vislumbra patterns em java.

Outra direção que deve ser muito seguida daqui para frente é o desenvolvimento de pattern para estruturas organizacionais, tais como setor bancário, telecomunicações, área médica, entre outros. Um exemplo é a coleção de patterns organizacionais produzidas por James Coplien. Eles descrevem como estruturar organizações e projetos para prover suporte apropriado para o gerenciamento dos projetos de desenvolvimento de software.

E, é claro, com a explosão na utilização e desenvolvimento de aplicativos para Internet, este não poderia faltar. Logo serão encontrados inúmeros patterns para a construção de soluções que envolvam a grande rede. Acompanhando a Internet, vêm os objetos distribuídos, principalmente na forma de soluções em CORBA.


REFERÊNCIAS BIBLIOGRÁFICAS

  1. AAMAD, Sane. Patterns homepage. Disponível na Internet. http://st-www.cs.uiuc.edu/users/ patterns/patterns.html

  2. ALEXANDER C., S. et al. A pattern language : towns buildings construction. Oxford University Press, 1977.

  3. A PATTERN definition. Disponível na Internet. http://hillside.net/patterns/ definition.html

  4. BUSCHMANN, Frank et al. Pattern - oriented software architecture: a system of patterns. New York : J. Wiley, 1996.

  5. COPLIEN, James O.; SCHIMIDT, Douglas C. Pattern language of program design. Reading : Addison-Wesley, 1995.

  6. FLOWER, Martin. Analysis patterns : reusable object models. Reading : Addison-Wesley, 1997.

  7. GAMMA, Erich et al. Design patterns: elements of reusable object-oriented software. Reading : Addison-Wesley, 1994.

  8. LEA, Doug. Christopher Alexander : an introduction for objetc – oriented designers. Disponível na Internet. http://g.oswego.edu/dl/ca/ca/ca.html

  9. RUMBAUGH, James et al. Object oriented modeling and design. Englewood Cliffs : Prentice Hall, 1991.

  10. SCHMIDT, Douglas C. et al. Software patterns. Disponível na Internet. http://www.cs.wustl.edu/~schmidt/CACM-editorial.html

  11. SHNEIDER, Manfred. Architecture and design. Disponível na Internet. http://www.cetus-links.org/oo_patterns.html