O objetivo deste texto é apresentar um tema que nos últimos anos tem ganhado a atenção da comunidade de software, que a cada dia é cobrada para projetar soluções de software com melhor qualidade e com o menor custo. Uma forma que contribui para a obtenção da qualidade de projetos de software são os padrões de projetos, em inglês design patterns.

No decorrer do texto será apresentada uma definição do que é e o que caracteriza um padrão de projeto, além de mostrar que o uso exagerado pode levar a situação inversa a que se propõem os padrões de projeto.

Introdução

Atualmente não se concebe um processo de desenvolvimento de software sério sem a utilização da orientação a objetos, pois esta permite agregar qualidades importantes aos sistemas desenvolvidos sob seus paradigmas, como a extensibilidade e a reusabilidade. Contudo, somente por estar utilizando-a, não é garantia de obter essas qualidades. Para criar as melhores soluções é preciso seguir um processo detalhado para obter uma análise dos requisitos, funcionais ou não funcionais, e desenvolver um projeto que os satisfaça e que possibilite submetê-los a teste para constatar eventuais falhas, se deseja que o projeto tenha uma arquitetura flexível para acomodar futuros problemas e requisitos sem a necessidade da realização do re-projeto.

Analisando o cotidiano do desenvolvimento de software é possível identificar que a procura por uma solução de um problema específico possui características idênticas, senão igual a encontrada em um projeto anteriormente desenvolvido, mas que devido à deficiência do processo, a solução e o problema não fora documentado e, às vezes, tão pouco compreendido em sua totalidade, impossibilitando o reaproveitamento das ideias e soluções. Desta forma, problemas idênticos que se repetem em outros contextos não são reconhecidos como tal, consumindo tempo e recursos em busca de soluções que em tese, já haviam sido encontradas.

Uma coisa que os projetistas avançados sabem que não devem fazer é resolver cada problema a partir de princípios elementares ou do zero. Ao invés disso, eles reutilizam soluções que funcionaram no passado, e os utilizam repetidamente em seus projetos. É como resolver um problema matemático até então inédito, ou pelo menos desconhecido a alguém. Primeiro utiliza-se todos os conhecimentos e princípios matemáticos que se tem conhecimento e que seja útil na solução. Depois de algumas tentativas e uso das teorias matemáticas, chega-se à solução e a partir daí tem-se um “algoritmo” (estrutura) montado que pode ser utilizado para resolver problemas que sejam idênticos ao resolvido. É por isso que os padrões de projetos, design patterns, tem chamado a atenção e despertado o interesse dos projetistas de software, por proporcionar elementos que conduzem ao reaproveitamento de soluções, e não apenas a reutilização de código.

Os padrões de projetos tornam mais fácil reutilizar soluções e arquiteturas bem sucedidas para construir softwares orientados a objetos de forma flexível e fácil de manter. O uso de padrões de projeto pode reduzir a complexidade do processo de projetar software. Além disso, o software orientado a objetos bem projetado possibilita aos projetistas reutilizar e empregar componentes preexistentes em sistemas futuros.

Em software, os padrões de projeto não são classes nem objeto. Em vez disso, os projetistas usam esses padrões para construir conjuntos de classes e objetos. Para utilizá-los de maneira eficaz, os projetistas precisam se familiarizar com os padrões mais populares e eficazes utilizados pela engenharia de software e conhecer o seu contexto e escopo.

A ideia de projetar soluções a partir de algo já conhecido e documentado não é nova e tão pouco teve origem na indústria de software, apesar de ela já demonstrar um interesse pelo tema. A ideia surgiu em 1977, quando Christopher Alexander publicou um catálogo com mais de 250 padrões para a arquitetura civil, que discutiam questões comuns da arquitetura, descrevendo em detalhe o problema e as justificativas de sua solução.

Christopher Alexander descobriu que diminuindo o foco, ou seja, procurando estruturas que resolvam problemas similares, ele pode discernir similaridades entre projetos de alta qualidade. Ele chamou essas similaridades de “padrões”.

Algum tempo depois ele formaliza seu método de descrição dos padrões, defendendo que seu uso não limitaria os arquitetos às soluções prescritas, mas garantiria a presença de elementos fundamentais, e a possibilidade de aperfeiçoá-la através das experiências adquiridas. Esse método chamou atenção da comunidade de software, fazendo que o tema ganhasse destaque nas conferências sobre orientação a objetos. Em 1995 Erich Gama, Richard Helm, Ralph Johnson, John Vlissides, conhecidos como os quatro amigos [Gang of Four - GoF], publicaram o livro sobre o título: “Design patterns – elements of reusable object-oriented software, Addison Wesley Longman”, que ganhou uma versão na língua portuguesa sobre o título de “Padrões de Projeto – Soluções reutilizáveis de software orientado a objetos. Bookman”. O livro é um catálogo que descreve 23 padrões de projeto cada um fornecendo uma solução para um problema de software, seu contexto, aplicação e suas eventuais conseqüências, dividindo-os em 3 categorias: padrões de criação, estruturais, e de comportamento.

Definindo padrões de projeto

Definir o que é um padrão de projeto de maneira clara e objetiva, tem sido o objetivo da comunidade de software, desde a década de 80.O primeiro a apresentar uma definição do que seria um padrão, foi o arquiteto de professor Christopher Alexandre, no seu livro “A Times Way of Building” (Oxford University Press, 1979), que é: “Cada padrão é uma regra de três partes, que expressa uma relação entre um certo contexto, um problema e uma solução”. Sendo assim para entender a necessidade, existência, de um padrão é necessário estudar suas partes: o problema, a solução e o contexto sobre o qual ele é aplicável.

Dessa forma, resumidamente pode-se entender como padrão de projeto, como a solução recorrente para um problema em um contexto, mesmo que em projetos e áreas distintas. Observe que os termos chaves dessa definição são: contexto, problema e solução, o que torna obrigatório à compreensão inequívoca de cada um. Um contexto diz respeito ao ambiente, e as circunstâncias dentro do qual algo existe. O problema é a questão indefinida, algo que precisa ser investigado e solucionado. Normalmente, está atrelado ao contexto em que ocorre. Finalmente, a solução refere à resposta do problema que ajuda a solucioná-lo.

Entretanto, se tivermos uma solução para um problema em um certo contexto, ela não necessariamente pode constituir um padrão, pois é necessário que ela tenha como característica a regularidade, isto é, ela se constituirá como um padrão se puder ser utilizada repetidamente.

Segundo Christopher Alexander, “cada padrão descreve um problema no nosso ambiente e o núcleo da sua solução, de tal forma que você possa usar esta solução mais de um milhão de vezes, sem nunca faze-lo da mesma maneira”.

O grupo dos quatro amigos classificou os padrões de projeto por dois critérios. O primeiro critério é a finalidade - reflete o que um padrão faz. Os padrões podem ter finalidades de criação, comportamento e estrutural. Os padrões de criação descrevem as técnicas para instanciar objetos (ou grupos de objetos), e possibilitam organizar classes e objetos em estrutura maiores, os de comportamento se caracterizam pela maneira pelas quais classes ou objetos interagem e distribuem responsabilidades e os estruturais lidam com a composição de classes ou objetos. O segundo critério é o escopo - especifica se o padrão é aplicado à classe ou objeto.

Características de um padrão de projeto

Embora um padrão seja a descrição de um problema, de uma solução genérica e sua justificativa, isso não significa que qualquer solução conhecida para um problema possa constituir um padrão, pois existem características obrigatórias que devem ser atendidas pelos padrões: .

  1. Devem possuir um nome, que descreva o problema, as soluções e consequências. Um nome permiti definir o vocabulário a ser utilizado pelos projetistas e desenvolvedores em um nível mais alto de abstração.
  2. Todo padrão deve relatar de maneira clara a qual (is)problema(s) ele deve ser aplicado, ou seja, quais são os problemas que quando inserido em um determinado contexto o padrão conseguirá resolvê-lo. Alguns podendo exigir pré-condições.
  3. Solução descreve os elementos que compõem o projeto, seus relacionamentos, responsabilidades e colaborações. Um padrão deve ser uma solução concreta, ele deve ser exprimido em forma de gabarito (algoritmo) que, no entanto, pode ser aplicado de maneiras diferentes.
  4. Todo padrão deve relatar quais são as suas consequências para que possa ser analisada a solução alternativa de projetos e para a compreensão dos benefícios da aplicação do projeto.

Não pode ser considerado um padrão de projeto trecho de códigos específicos, mesmo que para o seu criador ele reflita um padrão, que soluciona um determinado problema, porque os padrões devem estar a um nível maior de abstração e não limitado a recursos de programação. Um padrão de projeto nomeia, abstrai e identifica os aspectos chaves de uma estrutura de projeto comum para torná-la útil para a criação de um projeto orientado a objetos reutilizável.

A importância dos padrões de projeto

O mais importante sobre os padrões é que eles são soluções aprovadas. Cada catálogo inclui apenas padrões que foram considerados úteis por diversos desenvolvedores em vários projetos. Os padrões catalogados também são bem definidos; os autores descrevem cada padrão com muito cuidado e em seu próprio contexto, portanto será fácil aplicar o padrão em suas próprias circunstâncias. Eles também formam um vocabulário comum entre os desenvolvedores.

Quando os padrões não o ajudarão

Os padrões são um mapa, não uma estratégica. Os catálogos geralmente apresentarão algum código-fonte como uma estratégica de exemplo, portanto eles não devem ser considerados como definitivos. Os padrões não ajudarão a determinar qual aplicação você deve estar escrevendo apenas como implementar melhor a aplicação assim que o conjunto de recursos e outras exigências forem determinados. Os padrões ajudam com o que e como, mas não com por que ou quando.

O conceito de utilizar os padrões de forma indiscriminada é conhecida como antipadrões (anti patterns). De acordo com Andrew Koenig, se um padrão representa a “melhor prática”, então um antipadrão representa uma “lição aprendida”.

Existem duas noções de antipadrões:

  1. Aqueles que descrevem uma solução ruim para um problema que resultou em uma situação ruim;
  2. Aqueles que descrevem como se livrar de uma situação ruim e como proceder dessa situação para uma situação boa.

Em suma um antipadrão constitui ao uso indevido dos padrões de projeto, ou o seu uso exagerado, o que pode ser constatado pela utilização de padrões impróprios para um determinado contexto, ou uso inadequado. A utilização dos padrões proporciona um aumento na flexibilidade do sistema, entretanto pode deixá-lo mais complexo ou degradar a performance. Algumas perdas são toleráveis, mas subestimar os efeitos colaterais da adoção dos patterns, é um erro comum, principalmente daqueles que tomam o uso como um diferencial e não pela real necessidade.

Como padrões de projeto solucionam problemas de projeto

O alvo principal do uso dos padrões de projeto no desenvolvimento de software é o da orientação a objetos. Como os objetos são os elementos chaves em projetos OO, a parte mais difícil do projeto é a decomposição de um sistema em objetos. A tarefa é difícil porque muitos fatores entram em jogo: encapsulamento, granularidade, dependência, flexibilidade, desempenho, evolução, reutilização e assim por diante. Todos influenciam a decomposição, frequentemente de formas conflitantes.

Muito dos objetos participantes provêm do método de análise. Porém, projetos orientados a objetos acabam sendo compostos por objetos que não possui uma contrapartida no mundo real.

As abstrações que surgem durante um projeto são as chaves para torná-lo flexível. Os padrões de projeto ajudam a identificar abstrações menos óbvias bem como os objetos que podem capturá-las. Por exemplo, objetos que representam processo ou algoritmo não ocorrem na natureza, no entanto, eles são uma parte crucial de projetos flexíveis. Esses objetos são raramente encontrados durante a análise ou mesmo durante os estágios iniciais de um projeto; eles são descobertos mais tarde, durante o processo de tornar-se um projeto mais flexível e reutilizável.

Como selecionar um padrão de projeto

Escolher dentre os padrões existentes aquele que melhor soluciona um problema do projeto, sem cometer o erro de escolher de forma errônea e torná-lo inviável, é uma das tarefas mais difíceis. Em suma, a escolha de um padrão de projeto a ser utilizado, pode ser baseada nos seguintes critérios:

  1. Considerar como os padrões de projeto solucionam problemas de projeto.
  2. Examinar qual a intenção do padrão, ou seja, o que faz de fato o padrão de projeto, quais seus princípios e que tópico ou problema particular de projeto ele trata (soluciona).
  3. Estudar como os padrões se relacionam.
  4. Estudar as semelhanças existentes entre os padrões.
  5. Examinar uma causa de reformulação de projeto.
  6. Considerar o que deveria ser variável no seu projeto, ou seja, ao invés de considerar o que pode forçar uma mudança em um projeto, considerar o que você quer ser capaz de mudar sem reprojetá-lo.

Como usar um padrão de projeto

Depois de ter sido feita a escolha do(s) padrão(ões) a ser(em) utilizado(s) no projeto é necessária conhecer como utilizá-lo(s). Uma abordagem recomendada pela gangue dos quatros amigos para aplicar um padrão a um projeto é:

  1. Ler o padrão por completo uma vez, para obter sua visão geral. Conhecer o padrão principalmente a sua aplicabilidade e consequências são importantes para que ele realmente solucione o seu problema;
  2. Estudar seções Estrutura, Participantes e Colaborações. Assegurando-se de que compreendeu as classes e objetos no padrão e como se relacionam entre si;
  3. Escolher os nomes para os participantes do padrão que tenham sentido no contexto da aplicação;
  4. Definir as classes. Declarar as interfaces, estabelecer os seus relacionamentos de herança e definir as variáveis de instância que representam dados e referências a objetos. Identifique as classes existentes na aplicação que serão afetadas pelo padrão e modifique-as;
  5. Defina os nomes específicos da aplicação para as operações no padrão. Os nomes em geral dependem da aplicação. Use as responsabilidades e colaborações associadas com cada operação como guia;
  6. Implemente as operações para suportar as responsabilidades e colaborações presentes do padrão. A seção de Implementação oferece sugestões para guiá-lo na implementação.

Essas são apenas diretrizes que podem ser utilizadas até que seja obtido experiência e conhecimento necessário para desenvolver uma maneira de trabalho particular com os padrões de projeto. Os padrões de projeto não devem ser aplicados indiscriminadamente. Frequentemente eles obtêm flexibilidade e variabilidade pela introdução de níveis adicionais de endereçamento indireto, e isso pode complicar um projeto e/ou custar algo em termos de desempenho. Um padrão de projeto deverá apenas ser aplicado quando a flexibilidade que ele oferece for realmente necessária.

Principais padrões de projeto

Uma rápida leitura dos códigos da VCL (Visual Component Library) do Delphiconstata-se que ela fora construído fazendo uso intensivo dos padrões de projetos. O que é muito bom, pois constata o nível de excelência da ferramenta. Isto devido ao Delphiimplementar completamente as boas práticas da orientação a objetos – OOP, que auxiliam na implementação de projetos reutilizáveis.

Padrões de criação

Os padrões de criação são aqueles que abstraem e ou adiam o processo criação dos objetos. Eles ajudam a tornar um sistema independentemente de como seus objetos são criados, compostos e representados. Um padrão de criação de classe usa a herança para variar a classe que é instanciada, enquanto um padrão de criação de objeto delegará a instanciação para outro objeto.

Os padrões de criação tornam-se importantes à medida que os sistemas evoluem no sentido de dependerem mais da composição de objetos do que a herança de classes. O desenvolvimento baseado na composição de objetos possibilita que os objetos sejam compostos sem a necessidade de expor o seu interior como acontece na herança de classe, o que possibilita a definição do comportamento dinamicamente e a ênfase desloca-se da codificação de maneira rígida de um conjunto fixo de comportamentos, para a definição de um conjunto menor de comportamentos que podem ser compostos em qualquer número para definir comportamentos mais complexos.

Há dois temas recorrentes nesses padrões. Primeiro todos encapsulam conhecimento sobre quais classes concretas são usadas pelo sistema. Segundo ocultam o modo como essas classes são criadas e montadas. Tudo que o sistema sabe no geral sobre os objetos é que suas classes são definidas por classes abstratas. Consequentemente, os padrões de criação dão muita flexibilidade no que é criado, quem cria, como e quando é criado. Eles permitem configurar um sistema com objetos “produto” que variam amplamente em estrutura e funcionalidade. A configuração pode ser estática (isto é, especificada em tempo de compilação) ou dinâmica (em tempo de execução).

Abstract Factory

A intenção deste é fornecer uma interface para criação de famílias de objetos relacionados ou dependentes sem especificar suas classes concretas. Também é conhecido como Kit.

Este padrão deve ser aplicado quando se deseja isolar a aplicação da implementação da classe concreta, que poderia ser um componente e ou framework específico no qual a aplicação conheceria apenas uma interface e a implementação concreta seria conhecida apenas em tempo de execução ou compilação.

Imagine que em uma aplicação houvesse a necessidade de que ela fosse implementada para oferecer suporte a plataformas e características distintas. Por exemplo: Uma visão desktop e uma móvel (celular Pocket PC). A maneira de constituí-la, seria definindo uma família de componentes para cada plataforma e uma fábrica que os instancia de acordo com a plataforma alvo na qual a aplicação será executada.

De acordo com o exposto pelos quatro amigos, o uso do padrão Abstract Factory deve estar restrito as seguintes situações:

  • Um sistema deve ser independente de como seus produtos são criados, compostos ou representados;
  • Um sistema deve ser configurado como um produto de uma família de múltiplos produtos;
  • Uma família de objetos for projetada para ser usada em conjunto, e você necessita garantir esta restrição;
  • Você quer fornecer uma biblioteca de classes de produtos e quer revelar somente suas interfaces, não suas implementações.

A estrutura arquitetural do padrão definido segundo GoF é de acordo com o apresentado na Figura 1.

Estrutura arquitetural do pad
Figura 1. Estrutura arquitetural do padrão

A estrutura de um exemplo mais de acordo com a realidade do desenvolvedor é apresentada na Figura 2. A ideia básica apresentada pela figura é a de oferecer ao usuário (desenvolvedor) a possibilidade de executar uma aplicação sobre diferentes plataformas.

Diversas plataformas
Figura 2. Diversas plataformas

Os participantes são:

  • ComponentFactory-declara uma interface para operações que criam objetos dos componentes utilizados na aplicação;
  • PocketFactory– classe concreta que implementa as operações que criam os objetos no formato do dispositivo cliente;
  • PCFactory -classe concreta que implementa as operações responsáveis por criar os objetos no formato do PC.

O padrão Abstract Factory possui os seguintes benefícios e desvantagens:

  • Ele isola as classes concretas.
  • Ele torna fácil a troca de famílias de produtos.
  • Ela promove a harmonia entre produtos.
  • É difícil de suportar novos tipos de produtos.

Factory Method

Definir uma interface para criar objetos, mas deixar que as subclasses decidem que classe instanciar. O Factory Method, também conhecido como construtor virtual, possibilita adiar a criação do objeto a subclasses .

Esse padrão é comumente utilizado pelos projetistas de software quando existe a necessidade de encapsular a criação de uma classe se isolando do conhecimento da classe concreta da aplicação cliente através de uma interface. Essa necessidade é comumente desejada por aqueles que trabalham no desenvolvimento de frameworks, que utilizam classes abstratas para definir e manter relacionamentos entre os objetos. Dessa forma os clientes implementam as funcionalidades esperadas pelo framework adicionando a lógica de negócio específica da aplicação, sem que o framework tenha o conhecimento de como e qual a lógica implementada pela aplicação para complementá-lo.

Um exemplo de utilização do padrão pode ser na construção de aplicações que tenha que dar suporte a diferentes implementações de persistência com o mínimo de retrabalho.

A utilização do padrão Factory Method pode estar condicionada quando:

  1. Uma classe não pode antecipar a classe/tipo de objetos que devem criar;
  2. Uma classe especifique que suas subclasses tenham o conhecimento dos objetos que criam;
  3. Classes que delegam responsabilidade para uma dentre várias subclasses auxiliares, e você quer obter o conhecimento de qual subclasse auxiliar que é a delegada.

Os participantes são:

  • Product - define a interface de objetos que deverá ser criado pelo método fábrica;
  • ConcreteProduct – implementação da interface Product;
  • Creator – declara o método fábrica o qual retorna um objeto do tipoProduct;
  • ConcreteCreator – redefine(override) o método fábrica que retorna uma instância concreta da interfaceProduct.

O padrão Factory Method elimina a necessidade de anexar classes específicas das aplicações no código. O código lida somente com a interface de Product; portanto ele pode trabalhar com qualquer implementação da classe que implementa Product, definida pelo usuário.

Singleton

Garantir que um objeto terá apenas uma única instância, isto é, que uma classe irá gerar apenas um objeto e que este estará disponível de forma única para todo o escopo de uma aplicação.

Algumas aplicações têm a necessidade de controlar o número de instâncias criadas de algumas classes, seja pela necessidade da própria lógica ou por motivos de performance e economia de recursos.

Imagine o momento em que uma aplicação que exista simultaneamente num dispositivo móvel (Pocket PC, Celular, Palm) e num ambiente corporativo, necessite de um processo de sincronização entre as informações processadas no dispositivo móvel e na base corporativa. Ambas as aplicações deveriam se comunicar com um objeto que deveria ser único para processar este sincronismo, a fim de evitar a possibilidade de criar dados na base.

Elemento único de comunicação
Figura 3. Elemento único de comunicação

O uso do padrão Singleton está condicionado a:

  • Quando for necessário manter num sistema, seja ele distribuído ou não, apenas uma instância de objeto e que o ponto de acesso para este seja bem conhecido (Ex. objeto responsável por um pool de impressão numa rede, gerenciador de janelas);
  • Quando a única instância tiver de ser extensível através de subclasses, possibilitando aos clientes usarem uma instância estendida sem alterar o seu código (visões polimórficas).

Os desenvolvedores Delphi já utilizam o comportamento do padrão Singleton em suas aplicações, quando declaram variáveis globais na área de inicialização do projeto e depois reutilizam a instância dos objetos.TApplication, TCiipBoard são exemplos de objetos que não teriam sentido existir mais de uma instância na aplicação e por isso assumem o comportamento do padrão Singleton.

A estrutura do padrão é apresentada na Figura 4.

Estrutura do Sigleton
Figura 4. Estrutura do Sigleton

Os participantes são:

  1. Singleton –define um método estático que permite aos clientes obterem o objeto único. Ele também será responsável pelo processo de criação do objeto.

Os benefícios que o padrão apresenta são:

  • Acesso controlado a instância única;
  • Espaço de nomes reduzido (diga não a proliferação de variáveis globais);
  • Permite um refinamento de operações e representações;
  • Permite um número variável de instâncias - O padrão possibilita que seja adotada a estratégica de criar mais de uma instância da classe, de forma controlada;
  • Mais flexível do que as operações de classe;

Padrões estruturais

Os padrões estruturais se preocupam com a forma como classes e objetos são compostos para formar estruturas maiores. Os de classes utilizam a herança para compor interfaces ou implementações, e os de objeto ao invés de compor interfaces ou implementações, eles descrevem maneiras de compor objetos para obter novas funcionalidades. A flexibilidade obtida pela composição de objetos provém da capacidade de mudar a composição em tempo de execução o que não é possível com a composição estática (herança de classes).

Adapter

Converter a interface de uma classe por outra esperada pelos clientes . O que possibilita que classes com interfaces incompatíveis trabalhem em conjunto – ou que, de outra forma, seria impossível. Também conhecido como Wrapper (adaptador).

Algumas vezes, uma classe de um toolkit, projetada para ser reutilizada não condiz com a interface específica de um domínio requerida por uma aplicação.

O uso do padrão está condicionado a:

  1. Usar uma classe existente, mas sua interface não corresponde à interface requerida;
  2. Criar classes reutilizáveis que cooperam com classes não-relacionadas ou não previstas, ou seja, classes com interface inicialmente incompatível.

Os participantes são:

  1. Target (Alvo)–define a interface específica do domínio do cliente;
  2. Client (cliente) –colabora com objetos compatíveis com mTarget;
  3. Adaptee (Adaptação) –interface existente de necessita de adaptação;
  4. Adapter (Adaptador) –adapta a interface Adapte e à interface Target.

Para adaptações de classes:

  • Um adaptador de classe não funcionará quando quisermos adaptar uma classe e todas as suas subclasses;
  • Permite a Adapter substituir algum comportamento de Adaptee, já que adapterá uma subclasse.

Para adaptações de objetos:

  • Permite a um único Adapteradaptar um Adaptee e suas subclasses;
  • Torna mais difícil redefinir o comportamento de um Adaptee. Conseguido através de uma subclasse de Adaptee que é referenciada por Adapter.

Padrões de comportamento

Os padrões de comportamento se concentram nos algoritmos e atribuições de responsabilidades entre os objetos. Eles não descrevem apenas padrões de objetos ou de classes, mas também os padrões de comunicação entre os objetos.

Os padrões comportamentais de classes utilizam a herança para distribuir o comportamento entre classes, e os padrões de comportamento de objeto utilizam a composição de objetos em contrapartida a herança. Alguns descrevem como grupos de objetos cooperam para a execução de uma tarefa que não poderia ser executada por um objeto sozinho.

Template Method

Definir o esqueleto de um algoritmo em uma operação, postergando(deferring) alguns passos para subclasses. Template Method (gabarito de método) permite que subclasses redefinam certos passos de um algoritmo sem mudar a estrutura dele.

Agora imagine que você tenha de construir uma aplicação que possui uma determinada função da qual só é de conhecimento o algoritmo de execução, e o trabalho de codificação para realização da operação possa ser postergado. Observe a Figura 5.

Estrutura do padrão
Figura 5. Estrutura do padrão

Sobre a aplicabilidade desse padrão temos:

  • Para implementar as partes invariantes de um algoritmo e deixar para subclasses a implementação da parte variante;
  • Para fatorar o comportamento semelhante entre subclasses numa superclasse evitando-se assim a duplicação de código;
  • Para controlar extensões de classes com métodos "gancho";

Seus participantes são:

  • AbstractClass –define as operações primitivas e abstratas que representam os passos de um algoritmo e implementa um método que invoca estas operações primitivas;
  • ConcreteClass –implementa as operações específicas definidas na superclasse com o código específico.

Os métodos template são uma técnica fundamental para a reutilização de código. Eles conduzem a uma estrutura de inversão de controle em inglês Inversion of Control IoC ou princípio da dependência inversa, comumente conhecida como “o princípio de Hollywood”, ou seja: “não nos chame, nós chamaremos você”. Isto se refere a como uma classe-mãe chama as operações de uma subclasse, e não o contrário.

Conclusões

O uso de padrões de projeto propicia a construção de aplicações e ou estruturas de código de forma flexível e a documentação de soluções reaproveitáveis. Através dos padrões de projeto é possível identificar os pontos comuns entre duas soluções diferentes para um mesmo problema. Conhecer esses pontos comuns nos permite desenvolver soluções cada vez melhores e mais eficientes que podem ser reutilizadas, permitindo, assim, o avanço do conhecimento humano.

Os padrões possibilitam através de uma linguagem clara e concisa, que os projetistas experientes transfiram os seus conhecimentos aos mais novos em um alto nível de abstração e assim facilitam o desenvolvimento e o reaproveitamento de código.

Referências:
  • PAGE-JONES, Meilir. “Fundamentos do desenho orientado a objeto com UML”. 2 ed.São Paulo: Makron Books, 2001.
  • GAMMA, Erich, HELM, Richard; JOHNSON, Ralph, VLISSIDES, John.“Padrões de Projeto: soluções reutilizáveis de software orientado a objetos”. 1. ed. Porto Alegre: Bookman, 2000.
  • KOENIG, Andrew. Anti-Patterns. Última visita em 08 de fevereiro de 2005.
  • ALEXANDER, Christopher, et al. A Pattern Language. Oxford University Press, New York, 1977