padrões de projeto - design patterns

63
PÓS-GRADUAÇÃO EM ANÁLISE E GESTÃO DE SISTEMAS DE INFORMAÇÃO DÁVISSON HÚDSON CHAVES BERNADETE EDUARDO COELHO CARNEIRO FILIPE ARANTES FERNANDES PADRÕES DE PROJETO (DESIGN PATTERNS) Trabalho da Disciplina de Reutilização de Software Campos do Goytacazes, RJ 2013

Upload: davisson-hudson

Post on 15-Jul-2015

191 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Padrões de Projeto - Design Patterns

PÓS-GRADUAÇÃO EM ANÁLISE E GESTÃO DE SISTEMAS DE INFORMAÇÃO

DÁVISSON HÚDSON CHAVES BERNADETE EDUARDO COELHO CARNEIRO FILIPE ARANTES FERNANDES

PADRÕES DE PROJETO (DESIGN PATTERNS)

Trabalho da Disciplina de Reutilização de Software

Campos do Goytacazes, RJ

2013

Page 2: Padrões de Projeto - Design Patterns

RESUMO

Padrões de projeto são padrões que visam estruturar soluções para problemas antes encontrados em projetos de software, facilitando assim a criação de novos projetos já que apresentam soluções eficazes para problemas conhecidos. Padrões de projetos não são de fácil aplicação quando não se domina os conceitos que envolvem orientação a objetos, porém tornam-se de grande ajuda para desenvolvedores e projetistas mais experientes, facilitando bastante o trabalho. Padrões de projetos podem ser classificados de forma geral como de criação, estrutural e comportamental, cada tipo atua de forma diferente no tratamento dos objetos e classes. Padrões de projetos tendem a maximizar a qualidade do projeto, tornando-os mais flexíveis e possibilitando um melhor reuso de código. Os padrões de projeto mais conhecidos e utilizados são os 23 padrões do grupo conhecido como GoF (Gang of Four), e com base principal no trabalho deles, o presente trabalho aborda os padrões Abstract Factory, Decorator, Composite, Chain of Responsibility, Observer, Strategy, Template Method e Visitor com exemplos de código e explicações.

Page 3: Padrões de Projeto - Design Patterns

LISTA DE FIGURAS

Figura 1. Os 23 Padrões GoF (PEREIRA, 2013)............................................................................. 14

Figura 2. Estrutura do Padrão Abstract Factory (GAMMA et al., 2000) ...................................... 18

Figura 3. Diagrama de classe fábrica de carros (BRIZENO, 2011) ............................................... 20

Figura 4. Estrutura padrão do Composite ................................................................................... 23

Figura 5. Exemplo de implementação do padrão Composite ..................................................... 24

Figura 6. Estrutura do padrão Decorator .................................................................................... 29

Figura 7. Exemplo de implementação do padrão Decorator ...................................................... 30

Figura 8. Estrutura do Chain of Responsability ........................................................................... 34

Figura 9. Diagrama de classes do exemplo do padrão Chain of Responsability ......................... 37

Figura 10. Estrutura do padrão Observer (GAMMA et al, 2000). ............................................... 39

Figura 11. Diagrama de sequência entre um subject e dois observadores (GAMMA et al, 2000).

..................................................................................................................................................... 40

Figura 12. Diagrama de classes da estação meteorológica ......................................................... 41

Figura 13. Estrutura do Padrão Strategy (GAMMA et al., 2000). ................................................ 46

Figura 14. Diagrama de classe do exemplo do padrão Visitor. ................................................... 50

Figura 15. Diagrama de sequência do padrão Visitor ................................................................. 53

Figura 16. Diagrama de classes do exemplo de Visitor. .............................................................. 54

Page 4: Padrões de Projeto - Design Patterns

LISTA DE BLOCOS

Bloco 1. Interface FabricaDeCarro .............................................................................................. 20

Bloco 2. Classe FabricaFiat .......................................................................................................... 20

Bloco 3. Interfaces CarroPopular e CarroSedan .......................................................................... 21

Bloco 4. Implementação das interfaces CarroPopular e CarroSedan ......................................... 21

Bloco 5. Classe de teste da Fábrica de Carros ............................................................................. 22

Bloco 6. Implementação da classe MenuComponent ................................................................ 25

Bloco 7. Implementação da classe MenuItem ............................................................................ 26

Bloco 8. Implementação da classe Waitress ............................................................................... 26

Bloco 9. Implementação da classe MenuItem ............................................................................ 27

Bloco 10. Implementação da classe MenuTestDrive .................................................................. 28

Bloco 11. Implementação da classe Beverage ............................................................................ 31

Bloco 12. Implementação das classes dos condimentos ............................................................ 32

Bloco 13. Implementação da classe StarbuzzCoffee ................................................................... 33

Bloco 14. Implementação da enumeração de IDBancos ............................................................ 34

Bloco 15. Implementação da classe BancoChain ........................................................................ 35

Bloco 16. Implementação do banco concreto ............................................................................ 36

Bloco 17. Implemantação do padrão Chain of Responsability ................................................... 36

Bloco 18. Interfaces Subject, Observer e DisplayElement .......................................................... 42

Bloco 19. Classe WeatherData .................................................................................................... 43

Bloco 20. Implemnetação das interfaces Observer e DisplayElement em

CurrentConditionDisplay. ............................................................................................................ 44

Bloco 21. Criação do objeto weatherData e as 3 exibições ........................................................ 44

Bloco 22. Interface CalculaImposto ............................................................................................ 47

Bloco 23. Implementaação do imposto de 20% ou 15%. ............................................................ 48

Bloco 24. Método construtor de Funcionario. ............................................................................ 48

Bloco 25. Classe Usuario. ............................................................................................................ 50

Bloco 26. Classe AbstractLogin .................................................................................................... 51

Bloco 27. Classes LoginPorArquivo e LoginPorBD ....................................................................... 52

Bloco 28. Interfaces Visitable e Visitor. ....................................................................................... 55

Bloco 29. Classe abstrata Place ................................................................................................... 55

Bloco 30. Implementação de Visitable na classe City. ................................................................ 55

Bloco 31. Classes Museum e Park. .............................................................................................. 56

Bloco 32. Classe FirstTimeVisitor. ............................................................................................... 57

Bloco 33. Classe JobSeekerVisitor. .............................................................................................. 57

Page 5: Padrões de Projeto - Design Patterns

Sumário

1. INTRODUÇÃO .................................................................................................................... 7

1.1. MOTIVAÇÃO E JUSTIFICATIVA ............................................................................. 7

1.2. OBJETIVOS ................................................................................................................. 8

1.3. ORGANIZAÇÃO DO TRABALHO ............................................................................ 8

2. REFERENCIAL TEÓRICO ................................................................................................. 9

2.1. REUTILIZAÇÃO.......................................................................................................... 9

2.2. ENCAPSULAMENTO ................................................................................................. 9

2.3. HERANÇA, COMPOSIÇÃO, POLIMORFISMO E INTERFACE ........................... 10

2.4. MANUTENIBILIDADE E GRANULARIDADE ...................................................... 11

3. PADRÕES DE PROJETO (DESIGN PATTERNS) ........................................................... 12

3.1. PADRÕES DE CRIAÇÃO ......................................................................................... 14

3.2. PADRÕES ESTRUTURAIS ....................................................................................... 15

3.3. PADRÕES COMPORTAMENTAIS .......................................................................... 16

4. DESCREVENDO E EXEMPLIFICANDO ALGUNS PADRÕES .................................... 17

4.1. ABSTRACT FACTORY ............................................................................................ 17

4.1.1. Exemplo de Abstract Factory .............................................................................. 19

4.2. COMPOSITE .............................................................................................................. 22

4.2.1. Exemplo do Composite ........................................................................................... 24

4.3. DECORATOR ............................................................................................................ 29

4.3.1. Exemplo do Decorator ........................................................................................ 30

4.4. CHAIN OF RESPONSIBILITY ................................................................................. 33

4.4.1. Exemplo do Chain of Responsability ................................................................... 34

4.5. OBSERVER ................................................................................................................ 37

4.5.1. Exemplo de Observer .......................................................................................... 41

4.6. STRATEGY ................................................................................................................ 45

4.6.1. Exemplo de padrão Strategy ............................................................................... 47

4.7. TEMPLATE METHOD .............................................................................................. 49

4.7.1. Exemplo do Template Method ............................................................................ 49

4.8. VISITOR ..................................................................................................................... 53

4.8.1. Exemplo de Visitor .............................................................................................. 54

5. PADRÕES NÃO GOF ........................................................................................................ 58

5.1. SOA DESIGN PATTERNS ........................................................................................ 58

Page 6: Padrões de Projeto - Design Patterns

6. CONCLUSÕES ................................................................................................................... 59

6.1. CONTRIBUIÇÕES ..................................................................................................... 59

6.2. LIMITAÇÕES ............................................................................................................. 60

REFERÊNCIAS BIBLIOGRÁFICAS ........................................................................................ 61

Page 7: Padrões de Projeto - Design Patterns

7

1. INTRODUÇÃO

Padrões de projeto podem ser vistos como uma solução que já foi testada para

um problema, ou seja, geralmente descreve uma solução ou uma instância da solução

que foi utilizada para resolver um problema específico. Padrões de projetos são

soluções para problemas que alguém um dia teve e resolveu aplicando um modelo que

foi documentado e adaptado integralmente ou de acordo com a necessidade de uma

solução (MACORATTI, 2002).

Um padrão de projeto deve auxiliar e prever alterações de um projeto. Segundo

Freeman et al. (2004), alteração é a única coisa com a qual podemos contar sempre no

desenvolvimento de software, independentemente de como seja desenvolvido um

aplicativo, com o tempo ele precisa crescer e mudar para não morrer.

Os padrões de projeto nos dizem como resolver alguns problemas, porém não

dizem como adaptar esses projetos para adequá-los aos aplicativos, pois eles estão num

nível acima das bibliotecas (FREEMAN et al., 2004). Além disso, fornecem uma

linguagem compartilhada que pode maximizar o valor da comunicação entre

desenvolvedores.

1.1. MOTIVAÇÃO E JUSTIFICATIVA

Frequentemente desenvolvedores deparam-se com problemas que já foram

resolvidos em projetos anteriores, com isso surgiu a necessidade de se criar padrões

como uma ajuda na resolução de problemas baseados em soluções que já funcionavam

em projetos já desenvolvidos. Assim, o agrupamento dessas soluções tende a ajudar na

construção de projetos melhores e com maior manutenibilidade e granularidade.

Page 8: Padrões de Projeto - Design Patterns

8

1.2. OBJETIVOS

Este trabalho visa explorar os conceitos de Padrões de Projeto, bem como

apresentar exemplos de alguns padrões escolhidos. Este trabalho se baseia nos padrões

de Gamma et al. (2000), porém também são apresentados alguns padrões de projeto

diferentes da abordagem principal, não se restringindo necessariamente a uma única

linha de pesquisa.

1.3. ORGANIZAÇÃO DO TRABALHO

De forma geral o trabalho apresenta mais cinco capítulos além desta

introdução, conforme descrito a seguir.

No capítulo 2, é apresentado um referencial teórico, onde observa-se os

conceitos de reutilização de software, encapsulamento, herança, composição,

polimorfismo, interface, manutenibilidade e granularidade. Esses conceitos estão

presentes de forma intrínseca em um projeto de Padrão de Projetos e por isso ganharam

espaço no referencial teórico.

O capítulo 3 aborda de forma mais profunda questões sobre design patterns, o

que são e para que servem, as principais propriedades dos padrões de projeto,

apresentará os prós e os contras de se implantar um padrão de projeto em determinados

projetos, os componentes principais de um padrão de projeto, requisitos de um bom

sistema de padrões, e como se utilizar padrões de projeto.

No capítulo 4 alguns padrões foram escolhidos para exemplificar o estudo de

Design Patterns realizado, os exemplos foram feitos em Java na maior parte.

Alguns padrões não desenvolvidos ou agrupados por Gamma et al são

apresentados no capítulo 5, porém sem muita ênfase, apenas a título de informação.

No capítulo 6, e último, são apresentadas algumas conclusões obtidas durante o

desenvolvimento do trabalho.

Page 9: Padrões de Projeto - Design Patterns

9

2. REFERENCIAL TEÓRICO

2.1. REUTILIZAÇÃO

A Reutilização é uma atividade já realizada há muito tempo por

desenvolvedores e projetistas de software. Embora a mesma seja feita de uma maneira

ad hoc, ideias, objetos, argumentos e abstrações sempre foram reutilizados por

desenvolvedores de software (PRESSMAN, 2006).

A reutilização pode ser definida como o processo de criação de sistemas a

partir de software preexistente (KRUEGER, 1992), trazendo consigo a promessa de

aumentar a produtividade e diminuir custos de desenvolvimento, além de melhorar a

qualidade do produto, através de artefatos de software já testados e utilizados em outros

contextos (FRAKES e KANG, 2005).

A reutilização de software não é uma técnica nova, ela surgiu no final dos anos

60, porém, anteriormente, se reutilizava apenas bibliotecas de rotinas ou partes de

código em ambientes de programação, mas com a orientação a objeto (OO) passou-se a

utilizar as classes para encapsular dados e funções, aumentando a granularidade

(ODYSSEY, 2007). A reutilização representa uma subárea da Engenharia de Software,

esta busca melhorar a qualidade dos artefatos de software e diminuir o tempo e esforços

necessários para produzi-los, assim como a intenção da reutilização.

Em uma organização o desenvolvimento pode ser para ou com reutilização,

dependendo do interesse. O desenvolvimento de software para reutilização tem como

fim produzir os artefatos para que sejam reutilizados futuramente, e no desenvolvimento

de software com reutilização, artefatos são incorporados ao sistema (BERNADETE et

al., 2007).

2.2. ENCAPSULAMENTO

Encapsular, de forma geral, significa esconder os dados, ou seja, não deixar

campos expostos para serem manipulados diretamente a partir de código externo, o que

lavaria a violações da invariante de representação ou a dependências indesejáveis que

Page 10: Padrões de Projeto - Design Patterns

10

impedem a alteração da implementação (MACORATTI, 2002). Segundo Macoratti

(2002) devemos esconder alguns componentes, permitindo apenas acessos estilizados

ao objeto, porém o acesso indireto pode reduzir o desempenho.

O encapsulamento serve para controlar o acesso aos atributos e métodos de

uma classe, e também é uma forma eficiente de proteger os dados manipulados dentro

da classe, além de determinar onde esta classe poderá ser manipulada (LEMOS, 2013).

Então para ter um método encapsulado utilizamos um modificador de acesso que

geralmente é público, além do tipo de retorno dele (LEMOS, 2013).

Encapsular é fundamental para que o sistema seja suscetível a mudanças, assim

não é preciso mudar uma regra de negócio em vários lugares, mas sim em apenas um

único lugar, já que a regra está encapsulada (CAELUM, 2011).

2.3. HERANÇA, COMPOSIÇÃO, POLIMORFISMO E INTERFACE

As duas maneiras mais comuns para reutilização de funcionalidades em

sistemas orientados a objetos são herança de classe e composição de objetos, a herança

de classe permite definir a implementação de uma classe em termos da implementação

de outra, já a composição por objetos é uma alternativa á herança onde a nova

funcionalidade é obtida pela montagem ou composição de objetos para obter

funcionalidades mais complexas (GAMMA et al., 2000).

A herança é um mecanismo da Orientação a Objeto que permite criar novas

classes a partir de classes já existentes, aproveitando-se das características existentes na

classe a ser estendida (LEMOS, 2013). Com herança é possível criar classes derivadas,

subclasses e superclasses. Herança pode ser associada com o termo “é um”.

Composição estende uma classe e delega o trabalho para o objeto desta classe,

onde uma instância da classe existente é usada como componente da outra classe

(MACORATTI, 2011). Composição pode ser associada com o termo “tem um”.

Usando composição os objetos que foram instanciados e estão contidos na

classe que os instanciou são acessados somente através de sua interface, além disso,

uma composição deve ser definida dinamicamente em tempo de execução pela obtenção

de referência de objetos a objetos do mesmo tipo e apresenta uma menor dependência

de implementações (MACORATTI, 2011).

Page 11: Padrões de Projeto - Design Patterns

11

Uma interface nada mais é do que um bloco de código definindo um tipo e os

métodos e atributos que esse tipo deve possuir. Na prática o que acontece é que

qualquer classe que quiser ser do tipo definido pela interface deve implementar os

métodos dessa interface (LEMOS, 2013). Segundo a Caelum (2011), uma interface

pode ser vista como um “contrato”, onde quem assinar esse contrato é obrigado, nesse

caso, a implementar os métodos da interface, não se herda métodos e atributos, mas sim

responsabilidades. Uma interface pode herdar de mais de uma interface, o que pode nos

levar a um melhor uso do polimorfismo.

Polimorfismo é o princípio pelo qual duas ou mais classes derivadas de uma

mesma superclasse podem invocar métodos que têm a mesma identificação, assinatura,

mas comportamentos distintos, especializados para cada classe derivada (LEMOS,

2013). Polimorfismo é a capacidade de um objeto poder ser referenciado de várias

formas, porém isso não significa que o objeto fica se transformando, pelo contrário, um

objeto nasce de um tipo e morre do mesmo tipo, o que pode mudar é a maneira como

nos referimos a ele (CAELUM, 2011).

É sempre bom programar pensando na interface da classe, como seus usuários

a estarão utilizando, e não somente em como ela irá funcionar (GAMMA et al, 2000).

2.4. MANUTENIBILIDADE E GRANULARIDADE

Manutenibilidade é uma das características de qualidade de software,

determinando o grau de facilidade com que o mesmo pode ser corrigido ou

aperfeiçoado, assim um software com alto índice de manutenibilidade necessita de

menos tempo e pessoas para ser modificado (BRUSAMOLIN, 2004).

Manutenibilidade de software diz respeito à facilidade com que o mesmo pode

ser modificado para satisfazer requisitos do usuário ou ser corrigido quando deficiências

são detectadas (PIGOSKI, 1996).

Granularidade diz respeito ao nível de detalhamento da classe ou objeto, assim

quanto mais granular for um software, mais partes menores ele vai ter. Um sistema

granular tem um número maior de objetos com tarefas mais específicas, ao passo que

um sistema menos granular possui poucas classes, porém classes maiores, com mais

funcionalidades por exemplo.

Page 12: Padrões de Projeto - Design Patterns

12

Granularidade demais impacta no processamento e dificulta o

desenvolvimento, porém granularidade a menos deixa o código com pouca

manutenibilidade e menos coeso.

3. PADRÕES DE PROJETO (DESIGN PATTERNS)

Segundo Macoratti (2002), padrões para arquitetura de software são soluções

de eficiência já comprovadas e amplamente utilizadas para a resolução de problemas

comuns em projeto de software, que são desenvolvidas e conhecidas por especialistas e

tornam-se padrões por serem reutilizadas várias vezes em vários projetos, tendo eficácia

comprovada.

Padrões de projeto são descrições de objetos e classes comunicantes que

precisam ser personalizadas para resolver um problema geral de projeto num contexto

particular (GAMMA et al., 2000).

É importante observar que um padrão de projeto deve nomear, abstrair e

identificar os aspectos que dão base a uma estrutura de projeto comum para torná-la

reutilizável, focalizando um problema ou particularidade do projeto orientado a objetos.

A utilização de padrões possibilita uma maior coesão e minimização da

complexidade e do acoplamento entre os elementos que integram a aplicação

(PEREIRA, 2008).

Com um padrão de projeto é mais fácil reutilizar projetos e arquiteturas bem-

sucedidas, porém, somente devem ser considerados projetos que foram aplicados mais

de uma vez em diferentes sistemas, pois é necessário comprovar a eficiência e a eficácia

da solução para ser considerado um padrão de projeto, assim nenhum padrão de projeto

descreve projetos novos ou não testados.

Conhecer conceitos como abstração, herança e polimorfismo são importantes,

mas não suficientes para ser um bom projetista, é necessário criar projetos flexíveis que

sejam fáceis de manter e modificar (FREEMAN et al., 2004).

Segundo Gamma et al. (2000), um padrão tem quatro elementos essenciais:

nome, problema, solução e consequências. Eles descrevem esses elementos da seguinte

forma: o nome do padrão é uma referência que deve descrever um problema de projeto,

suas soluções e consequências em uma ou duas palavras; o problema descreve em que

Page 13: Padrões de Projeto - Design Patterns

13

situação aplicar o padrão, deve explicar o problema e seu contexto; a solução descreve

os elementos que compõem o padrão de projeto, seus relacionamentos, suas

responsabilidades e colaborações, o padrão fornece uma descrição abstrata de um

problema de projeto e como um arranjo geral de elementos o resolve; as consequências

são os resultados e análises das vantagens e desvantagens da aplicação do padrão.

Dentre as principais propriedades dos padrões de projetos podemos citar que

capturam o conhecimento e a experiência de especialistas em projetos de software,

auxiliam o projeto de arquiteturas mais complexas (MACORATTI, 2002), especificam

abstrações que estão acima do nível de classes ou objetos isolados ou de componentes e

definem um vocabulário comum para discussão de problemas e soluções de projeto

(GAMMA et al., 2000), facilitam a documentação e manutenção da arquitetura do

software e também auxiliam o projeto de uma arquitetura com determinadas

propriedades (BUSCHMANN et al., 1996).

Como benefícios da utilização de padrões podemos destacar, segundo

Macoratti (2002):

• Fornecem soluções que já foram testadas e aprovadas.

• Tornam o sistema mais fácil de entender e manter.

• Facilitam o desenvolvimento de módulos coesos.

• A comunicação entre os participantes do projeto fica mais eficiente.

Como desvantagens pode-se citar o aumento da complexidade de entendimento

se não houver grande conhecimento de conceitos OO por parte dos envolvidos, e

também por adicionar acessos indiretos ou ao aumentar a quantidade de código, contudo

podem aumentar a capacidade de compreensão ao melhorar a modularidade, separando

melhor os conceitos e simplificando a descrição (UNIVERSIA).

Os requisitos para um bom sistema de padrões segundo Macoratti (2002): o

sistema deve conter uma boa quantidade de padrões; a descrição do padrão de seguir um

formato padronizado; o sistema deve ser estruturado; o sistema deve mostrar o

relacionamento entre os padrões e sua estrutura deve permitir evolução.

Para se utilizar padrões devemos ter bom senso, não adianta sair

implementando padrões sem ter certeza do porque utilizá-los, então o melhor é

implementar a solução e verificar se ela funciona para assim poder refatorá-la com os

padrões identificados para a melhoria e correção das deficiências do projeto.

Page 14: Padrões de Projeto - Design Patterns

14

Os padrões criados por Gamma et al. (2000) são os mais conhecidos

atualmente, e de acordo com eles os padrões podem ser de 3 tipos: padrões de criação,

estruturais e comportamentais. A figura 1 mostra a divisão dos padrões.

Figura 1. Os 23 Padrões GoF (PEREIRA, 2013)

3.1. PADRÕES DE CRIAÇÃO

Os padrões de criação abstraem o processo de instanciação, ajudam a tornar um

sistema independente de como seus objetos são criados, compostos e representados

(GAMMA et al., 2000).

Todos os padrões de criação encapsulam conhecimento sobre quais classes

concretas são usadas pelo sistema, e todas ocultam o modo como as instâncias destas

classes são criadas e compostas, a única coisa que o sistema sabe é que suas classes são

definidas por classes abstratas (GAMMA et al., 2000). Porém um padrão de criação dá

muita flexibilidade ao que, como e quando é criado e a quem cria (GAMMA et al.,

2000).

Uma descrição geral dos padrões de criação é apresentada a seguir.

Abstract Factory – Fornece uma interface para criação de famílias de objetos

relacionadas ou dependentes sem especificar suas classes concretas.

Builder – Separa a construção de um objeto complexo da sua representação, de

forma que o mesmo processo de construção possa criar diferentes representações.

Page 15: Padrões de Projeto - Design Patterns

15

Factory Method – Define uma interface para instanciação de objetos, mas deixa

as subclasses decidirem qual classe deve ser instanciada.

Prototype – Especifica os tipos de objetos a serem criados usando uma

instância prototípica e cria novos objetos copiando esse protótipo.

Singleton – Garante que para uma classe específica só possa existir uma única

instância, fornecendo um ponto global de acesso para ela.

3.2. PADRÕES ESTRUTURAIS

Os padrões estruturais se preocupam com a forma como classes e objetos são

compostos para formar estruturas maiores, eles utilizam herança para compor interfaces

ou implementações (GAMMA et al., 2000). Este tipo de padrão é bastante útil para

fazer bibliotecas de classes independentes trabalharem juntas.

Nesse padrão os padrões estruturais de objetos descrevem maneiras de compor

objetos para obter novas funcionalidades, assim a flexibilidade obtida pela composição

de objetos provém da capacidade de mudar a composição em tempo de execução

(GAMMA et al., 2000).

Uma descrição geral dos padrões estruturais é apresentada a seguir.

Adapter – Converte a interface de uma classe em outra interface esperada pelos

clientes. Permite que dois objetos se comuniquem mesmo que tenham interfaces

incompatíveis.

Bridge – Separa uma abstração de sua implementação, de forma que as duas

possam variar independentemente. Oculta detalhes de implementação dos clientes.

Composite – Permite que os clientes tratem objetos individuais e composições

de objetos de maneira uniforme. Ele lida com uma estrutura de elementos agrupada

hierarquicamente.

Decorator – Atribui responsabilidades adicionais a um objeto dinamicamente.

Ele fornece uma alternativa flexível a subclasses para a extensão da funcionalidade.

Facade – Fornece uma interface unificada para u conjunto de interfaces em um

subsistema, tornando o subsistema mais fácil de usar.

Flyweight – Usa compartilhamento para dar suporte a vários objetos de forma

eficiente.

Page 16: Padrões de Projeto - Design Patterns

16

Proxy – Fornece um objeto representante ou procurador de outro objeto para

controlar o acesso ao mesmo.

3.3. PADRÕES COMPORTAMENTAIS

Este tipo de padrão se preocupa com algoritmos e a atribuição de

responsabilidade entre objetos, eles não descrevem somente padrões de objetos ou

classes, mas também os padrões de comunicação entre eles, contudo, caracterizam

fluxos de controle difíceis de seguir em tempo de execução (GAMMA et al., 2000).

Padrões comportamentais de classe utilizam herança para distribuir o

comportamento entre as classes enquanto os padrões comportamentais de objetos

utilizam composição de objetos (GAMMA et al., 2000).

Uma descrição geral dos padrões comportamentais é apresentada a seguir.

Chain of Responsibility – Evita dependência do remetente (cliente) de uma

requisição ao seu destinatário, dando a oportunidade de mais de um objeto tratar a

requisição. Ele encadeia os objetos receptores e passa a solicitação ao longo da cadeia

até que um objeto a trate.

Command – Encapsula uma solicitação como um objeto, permitindo

parametrizar clientes com diferentes solicitações, enfileirar ou registrar solicitações e

suportar operações que podem ser desfeitas.

Interpreter – Dada uma linguagem, define-se uma representação para sua

gramática juntamente com um interpretador que usa a representação para interpretar

sentenças nessa linguagem.

Iterator – Provê uma forma de percorrermos os elementos de uma coleção sem

violar o seu encapsulamento.

Mediator – Cria um objeto que age como um mediador controlando a interação

entre um conjunto de objetos, ou seja, encapsula a forma como um conjunto de objetos

interage.

Memento – Torna possível salvar o estado de um objeto de modo que o mesmo

possa ser restaurado, sem violar o encapsulamento.

Observer – Define uma relação de dependência 1:N de forma que quando um

certo objeto (assunto) tem seu estado modificado os demais (observadores) são

Page 17: Padrões de Projeto - Design Patterns

17

notificados e atualizados. Possibilita baixo acoplamento entre os objetos observadores e

o assunto.

State – Permite a um objeto alterar seu comportamento quando estado interno

muda.

Strategy – Define uma família de algoritmos, encapsula cada um deles e os

torna intercambiáveis. Permite que o algoritmo varie independentemente dos clientes

que o utilizam.

Template Method – Define o esqueleto de um algoritmo em uma operação

adiando a definição de alguns passos para as subclasses. Ele permite que as subclasses

redefinam certos passos de um algoritmo sem mudar a sua estrutura.

Visitor – Define operações independentes a serem realizadas sobre elementos

de uma estrutura.

4. DESCREVENDO E EXEMPLIFICANDO ALGUNS PADRÕES

Este capítulo apresenta alguns padrões escolhidos para exemplificar o estudo

de Design Patterns realizado. Os exemplos são exibidos em Java e/ou Python.

4.1. ABSTRACT FACTORY

Criar objetos é mais do que simplesmente usar o operador new, criar instâncias

nem sempre deve ser feito de forma pública, isso pode gerar problemas de ligação

(FREEMAN et al., 2004). Os padrões Factory podem ajudar nessa situação. As

factories (fábricas) cuidam dos detalhes da criação dos objetos.

Segundo Gamma et al. (2000), o padrão Abstract Factory, também conhecido

como kit, fornece uma interface para criação de famílias de objetos relacionados ou

dependentes sem especificar suas classes concretas.

Abstract Factory permite que um cliente use uma interface abstrata para criar

um conjunto de produtos relacionados se saber, ou importar-se, sobre os produtos

Page 18: Padrões de Projeto - Design Patterns

concretos que são realmente produzidos, assim o cliente é desvinculado de qualquer

especificação dos produtos concretos (FREEMAN

Segundo Gamma et al

• Um sistema deve ser independente de como seus produtos

compostos ou representados;

• Um sistema deve ser configurado como um produto de uma família de

múltiplos produtos;

• Uma família de objetos

conjunto, e for necessário garantir essa restrição;

• Intende-se fo

revelar-se somente suas interfaces, não suas implementações.

Baseado em Gamma

Figura 2. Estrutura do Padrão Abstract

Assim temos os participantes de acordo

compilação de Gamma et al

• AbstractFactory

objetos-produto abstratos

concretas devem implementar, o que consiste em um conjunto de

métodos para fabricar produtos;

• Concrete Factory

concretos.

que são realmente produzidos, assim o cliente é desvinculado de qualquer

especificação dos produtos concretos (FREEMAN et al., 2004).

et al. (2000), este padrão deve ser aplicado quando:

Um sistema deve ser independente de como seus produtos

compostos ou representados;

Um sistema deve ser configurado como um produto de uma família de

múltiplos produtos;

Uma família de objetos-produto for projetada para ser usada em

conjunto, e for necessário garantir essa restrição;

se fornecer uma biblioteca de classes de produtos e quer

se somente suas interfaces, não suas implementações.

Baseado em Gamma et al. (2000) a estrutura do padrão é apresentada a seguir:

. Estrutura do Padrão Abstract Factory (GAMMA et al., 2000)

Assim temos os participantes de acordo da figura 2 explicitados segundo uma

et al. (2000) e Freeman et al. (2004):

Factory – Declara uma interface para operações que criam

produto abstratos. Define a interface que todas as fábricas

concretas devem implementar, o que consiste em um conjunto de

métodos para fabricar produtos;

Concrete Factory – Implementa as operações que criam objetos

As fábricas concretas implementam as diferentes famílias de

18

que são realmente produzidos, assim o cliente é desvinculado de qualquer

. (2000), este padrão deve ser aplicado quando:

Um sistema deve ser independente de como seus produtos são criados,

Um sistema deve ser configurado como um produto de uma família de

produto for projetada para ser usada em

rnecer uma biblioteca de classes de produtos e quer

se somente suas interfaces, não suas implementações.

. (2000) a estrutura do padrão é apresentada a seguir:

explicitados segundo uma

Declara uma interface para operações que criam

. Define a interface que todas as fábricas

concretas devem implementar, o que consiste em um conjunto de

mplementa as operações que criam objetos-produto

ferentes famílias de

Page 19: Padrões de Projeto - Design Patterns

19

produtos, e para criar um produto o cliente usa uma dessas fábricas,

assim nunca precisa criar a instância do objeto de um produto;

• AbstractProduct – Declara uma interface para um tipo de objeto-

produto. É a família de produtos onde cada fábrica concreta pode

produzir um conjunto inteiro de produtos;

• ConcreteProduct – Define um objeto-produto a ser criado pela

correspondente fábrica concreta. Também implementa a interface de

Abstract Product.

• Client – Usa somente interfaces declaradas pelas classes Abstract

Factory e Abstract Product. Em suma, é escrita para a Abstract Factory

e, depois, composta no tempo de execução com a Abstract Product.

Uma única instância de uma classe ConcreteFactory é criada em tempo de

execução normalmente. Para criar diferentes objetos-produto, os clientes deveriam usar

fábricas concretas diferentes (GAMMA et al., 2000).

Segundo Freeman et al. (2000), geralmente os métodos de uma Abstract

Factory são implementados como Factory Methods. O trabalho de uma Abstract Factory

é definir uma interface para criar um conjunto de produtos, e cada método nessa

interface é responsável pela criação de um produto concreto, assim implementamos uma

subclasse da Abstract Factory para fornecer essas implementações, dessa forma

percebe-se que os Factory Methods são uma forma natural de implementar métodos

concretos nas Abstract Factory.

As classes Abstract Factory são frequentemente implementadas com Factory

Methods, mas elas também podem ser implementadas usando Prototype, além disso,

uma fábrica concreta é frequentemente um Singleton (GAMMA et al., 2000).

As consequências de se usar esse padrão são apontadas por Gamma et al.

(2000): Isolamento das classes concretas; fácil troca de famílias de produtos; promove

harmonia entre produtos; difícil de suportar novos tipos de produtos.

4.1.1. Exemplo de Abstract Factory

Para Abstract Factory utilizou-se o exemplo de Brizeno (2011), que consiste na

representação de um sistema que, dado um conjunto de carros devemos manipulá-los.

Page 20: Padrões de Projeto - Design Patterns

Deve ser feito um agrupamento dos carros em conjuntos, de forma a agrupar objetos

que tenham comportamentos parecidos.

Para exemplificar os objetos foram organizados da seguinte forma:

Sedan (Siena – Fiat

Popular (Palio – Fiat

Assim o que deve ser feito é agrupar

conjunto de carros Popular para cada uma das fábricas.

do projeto de fábricas de carros Sedan e Popular.

Figura 3. Diagrama de c

O bloco 1 mostra uma interface para criação de Factories. Cada fábrica cria um

objeto de cada tipo, nesse caso um método para carros Sedan e outro para carros

Populares.

public class FabricaFiat

@Override

public CarroSedan criarCarroSedan() {

return new Siena();

}

@Override

public CarroPopular criarCarroPopular(

return new Palio();

}

public interface FabricaDeCarro {

CarroSedan criarCarroSedan();

CarroPopular criarCarroPopular();

}

agrupamento dos carros em conjuntos, de forma a agrupar objetos

que tenham comportamentos parecidos.

Para exemplificar os objetos foram organizados da seguinte forma:

Fiat, Fiesta Sedan – Ford);

Fiat, Fiesta – Ford).

o que deve ser feito é agrupar um conjunto de carros S

conjunto de carros Popular para cada uma das fábricas. A figura 3 apresenta a estrutura

do projeto de fábricas de carros Sedan e Popular.

. Diagrama de classe fábrica de carros (BRIZENO, 2011)

mostra uma interface para criação de Factories. Cada fábrica cria um

objeto de cada tipo, nesse caso um método para carros Sedan e outro para carros

FabricaFiat implements FabricaDeCarro {

CarroSedan criarCarroSedan() {

Siena();

CarroPopular criarCarroPopular() {

Palio();

FabricaDeCarro {

CarroSedan criarCarroSedan();

CarroPopular criarCarroPopular();

Bloco 1. Interface FabricaDeCarro

Bloco 2. Classe FabricaFiat

20

agrupamento dos carros em conjuntos, de forma a agrupar objetos

Para exemplificar os objetos foram organizados da seguinte forma:

um conjunto de carros Sedan e outro

apresenta a estrutura

mostra uma interface para criação de Factories. Cada fábrica cria um

objeto de cada tipo, nesse caso um método para carros Sedan e outro para carros

Page 21: Padrões de Projeto - Design Patterns

21

O bloco 2 cria os carros de fato, instanciando-os.

Todas as outras fábricas necessitam implementar a interface FabricaDeCarro.

A seguir a criação de mais duas interfaces:

Os dois métodos apresentados nas interfaces do bloco 3 exibem as informações

de seus tipos de carro, e apesar dos métodos executarem a mesma operação poderíamos

supor que os carros populares estão em um banco de dados e os sedans em outro, assim

cada método precisa criar sua própria conexão.

O bloco 4 apresenta os produtos concretos implementando suas interfaces.

public class Palio implements CarroPopular { @Override public void exibirInfoPopular() { System.out.println("Modelo: Palio\nFábrica: Fiat\nCategoria:Popular");

} } public class Siena implements CarroSedan { @Override public void exibirInfoSedan() { System.out.println("Modelo: Siena\nFábrica: Fiat\nCategoria:Sedan"); } }

public interface CarroPopular {

void exibirInfoPopular();

}

public interface CarroSedan {

void exibirInfoSedan();

}

Bloco 3. Interfaces CarroPopular e CarroSedan

Bloco 4. Implementação das interfaces CarroPopular e CarroSedan

Page 22: Padrões de Projeto - Design Patterns

22

Analisando o bloco 5 percebe-se que foi criada uma fábrica abstrata e foi

colocado nela qualquer fábrica, de acordo com a necessidade, e de forma semelhante foi

criada referências para um carro Popular e para um carro Sedan, e ainda de acordo com

nossas necessidades foram sendo utilizados os carros dos fabricantes.

Segundo Brizeno (2011) com esse padrão criamos uma estrutura muito grande

de classes e interfaces para resolver o problema de criação de objetos, porém baseado

no princípio da Segregação de Interface isto é uma coisa boa, pois o código cliente fica

dependendo de interfaces simples e pequenas ao invés de depender de uma interface

grande e que nem todos os métodos seriam utilizados.

4.2. COMPOSITE

O Composite é um tipo de padrão estrutural e tem como objetivo permitir a

composição de objetos em estruturas de árvore para representar hierarquias parte-todo

possibilitando o tratamento de objetos individuais ou composições de objetos de modo

uniforme.

Segundo Gamma et al. (2000), Composite deve tratar objetos primitivos e

objetos recipientes de modo diferente, mesmo se na maior parte do tempo o usuário os

trata de forma idêntica. Ter que distinguir entre esses objetos torna a aplicação mais

complexa. O padrão Composite descreve como usar a composição recursiva de maneira

que os clientes não tenham que fazer essa distinção.

public static void main(String[] args) { FabricaDeCarro fabrica = new FabricaFiat(); CarroSedan sedan = fabrica.criarCarroSedan(); CarroPopular popular = fabrica.criarCarroPopular(); sedan.exibirInfoSedan(); System.out.println(); popular.exibirInfoPopular(); System.out.println();

fabrica = new FabricaFord(); sedan = fabrica.criarCarroSedan(); popular = fabrica.criarCarroPopular(); sedan.exibirInfoSedan(); System.out.println(); popular.exibirInfoPopular(); }

Bloco 5. Classe de teste da Fábrica de Carros

Page 23: Padrões de Projeto - Design Patterns

O segredo do padrão é a

representa tanto as primitivas

operações que todos os objetos compostos compartilham, tais como operações para

acessar e manipular seus filhos.

demonstrada na Figura 4,

para filhos e composições.

Será de fácil compreensão se olharmos a estrutura como uma árvore de cabeça

para baixo. Um nó pode ter filhos e também um nó que, por sua vez, pode ter outros

filhos e nós. Neste padrão,

sendo declaradas em Component

classe só deve ter uma responsabilidade, no qual o padrão

De acordo com Freeman (2004)

Responsabilidade Única e o troca pela transparência. O fato de o cliente lidar

uniformemente com os compostos e os nó

Contudo, como as operações estão sendo declaradas na classe

pouco de segurança, pois um cliente pode tentar fazer algo inadequado ou sem sentido

com um elemento. Isto é decisão de projeto; pode

direção, separando as responsabilidades em diferentes interfaces. Isto tornaria o projeto

seguro, no sentido de que quaisquer chamadas inadequadas de elementos seriam

detectadas por ocasião da compilação ou da execução. Poré

transparência, e o código necessitaria de usar condicionais e o operador

Portanto, esse é um típico caso de que se perde algo para obter algum benefício.

Um projetista deve ser guiado pelos princípios de projeto, mas deve f

no efeito que eles têm sobre os projetos. Alguma modelagem pode parecer desrespeitar

O segredo do padrão é a recursividade devido a uma classe abstrata que

representa tanto as primitivas como os seus recipientes. Esta classe abstrata declara

operações que todos os objetos compostos compartilham, tais como operações para

acessar e manipular seus filhos. Por exemplo, observando a estrutura padrão

, a classe Component declara métodos que são utilizados só

para filhos e composições.

Figura 4. Estrutura padrão do Composite

Será de fácil compreensão se olharmos a estrutura como uma árvore de cabeça

o. Um nó pode ter filhos e também um nó que, por sua vez, pode ter outros

, nota-se que Leaf herda operações de Composite

Component. Segundo princípios de orientação a objetos, uma

uma responsabilidade, no qual o padrão Composite não respeita.

De acordo com Freeman (2004), o padrão abre mão do princípio de projetos da

Responsabilidade Única e o troca pela transparência. O fato de o cliente lidar

com os compostos e os nós-folha é caracterizado transparência.

Contudo, como as operações estão sendo declaradas na classe Component

pouco de segurança, pois um cliente pode tentar fazer algo inadequado ou sem sentido

com um elemento. Isto é decisão de projeto; pode-se conduzir o processo em outra

direção, separando as responsabilidades em diferentes interfaces. Isto tornaria o projeto

seguro, no sentido de que quaisquer chamadas inadequadas de elementos seriam

detectadas por ocasião da compilação ou da execução. Porém, poderia perder a

transparência, e o código necessitaria de usar condicionais e o operador

Portanto, esse é um típico caso de que se perde algo para obter algum benefício.

deve ser guiado pelos princípios de projeto, mas deve ficar atento sempre

no efeito que eles têm sobre os projetos. Alguma modelagem pode parecer desrespeitar

23

uma classe abstrata que

como os seus recipientes. Esta classe abstrata declara

operações que todos os objetos compostos compartilham, tais como operações para

observando a estrutura padrão

declara métodos que são utilizados só

Será de fácil compreensão se olharmos a estrutura como uma árvore de cabeça

o. Um nó pode ter filhos e também um nó que, por sua vez, pode ter outros

Composite que estão

Segundo princípios de orientação a objetos, uma

não respeita.

o padrão abre mão do princípio de projetos da

Responsabilidade Única e o troca pela transparência. O fato de o cliente lidar

é caracterizado transparência.

Component, perde-se um

pouco de segurança, pois um cliente pode tentar fazer algo inadequado ou sem sentido

se conduzir o processo em outra

direção, separando as responsabilidades em diferentes interfaces. Isto tornaria o projeto

seguro, no sentido de que quaisquer chamadas inadequadas de elementos seriam

m, poderia perder a

transparência, e o código necessitaria de usar condicionais e o operador instanceof.

Portanto, esse é um típico caso de que se perde algo para obter algum benefício.

icar atento sempre

no efeito que eles têm sobre os projetos. Alguma modelagem pode parecer desrespeitar

Page 24: Padrões de Projeto - Design Patterns

algum princípio, porém, tudo é uma questão de perspectiva. De acordo com Freeman

(2004), talvez pareça incorreto ter operações de gerenciamento de filho

mas pode-se deslocar um pouco a perspectiva e ver uma folha como um nó com zero

filhos.

4.2.1. Exemplo do CompositePara implementar este tipo de padrão, é

(2004) demonstrado na Figura

Figura 5

De forma resumida, a classe

na composição; implementa comportamento

classes, conforme apropriado; declara uma interface para acessar e gerenciar os seus

componentes-filhos e defin

estrutura recursiva e a implementa. Em

composição (um item de menu

menu em menu. Na classe

filhos; armazena os itens de menu e implementa as operações relacionadas com os

filhos presentes na interface de

os objetos na composição através da interface de

algum princípio, porém, tudo é uma questão de perspectiva. De acordo com Freeman

(2004), talvez pareça incorreto ter operações de gerenciamento de filho

se deslocar um pouco a perspectiva e ver uma folha como um nó com zero

Exemplo do Composite mentar este tipo de padrão, é abordado um exemplo de Freeman

Figura 5.

5. Exemplo de implementação do padrão Composite

De forma resumida, a classe MenuComponent declara a interface para os objetos

na composição; implementa comportamento-padrão para a interface comum a todas a

classes, conforme apropriado; declara uma interface para acessar e gerenciar os seus

define uma interface para acessar o pai de um componente na

estrutura recursiva e a implementa. Em MenuItem, representa objetos

um item de menu não tem filhos) e define comportamento para

Na classe Menu, define comportamento para componentes que têm

itens de menu e implementa as operações relacionadas com os

ce de MenuComponent. E Waitress é a classe que manipula

os objetos na composição através da interface de MenuComponent.

24

algum princípio, porém, tudo é uma questão de perspectiva. De acordo com Freeman

(2004), talvez pareça incorreto ter operações de gerenciamento de filhos nos nós-folha,

se deslocar um pouco a perspectiva e ver uma folha como um nó com zero

abordado um exemplo de Freeman

declara a interface para os objetos

padrão para a interface comum a todas as

classes, conforme apropriado; declara uma interface para acessar e gerenciar os seus

uma interface para acessar o pai de um componente na

objetos-folha na

comportamento para os itens do

, define comportamento para componentes que têm

itens de menu e implementa as operações relacionadas com os

é a classe que manipula

Page 25: Padrões de Projeto - Design Patterns

25

A implementação da classe MenuComponent é demonstrada no Bloco 6. É

nítido que esta classe só estabelece o contrato das operações deixando a cargo de suas

sub-classes a implementação de cada operação que lhe interessa.

Bloco 6. Implementação da classe MenuComponent

Em MenuItem, é implementado as operações que dizem respeito aos itens de

menu, ou seja, não é possível implementar a operação add, pois não faz sentido um item

de menu ter um filho, demonstrado no Bloco 7.

As operações referentes a um menu, são implementadas na classe Menu,

apresentada no Bloco 9. Menu é do tipo MenuComponent e que, por sua vez, pode ter

qualquer quantidade de filhos do tipo MenuComponents. Com a herança mais

composição é possível ter a recursividade desejada.

Tanto em MenuItem quanto Menu, possuem as mesmas operações, como por

exemplo print. Em MenuItem, basta somente imprimir o nome, se é um tipo de comida

vegetariana, o preço e a descrição. Já em Menu, a operação print deverá imprimir seu

public abstract class MenuComponent{ public void add(MenuComponent menuComponent){ throw new UnsupportedOperationException(); } public void remove(MenuComponent menuComponent){ throw new UnsupportedOperationException(); } public MenuComponent getChild(int i){ throw new UnsupportedOperationException(); } public String getName(){ throw new UnsupportedOperationException(); } public String getDescription(){ throw new UnsupportedOperationException(); } public double getPrice(){ throw new UnsupportedOperationException(); } public boolean isVegetarian(){ throw new UnsupportedOperationException(); } public void print(){ throw new UnsupportedOperationException(); } }

Page 26: Padrões de Projeto - Design Patterns

26

nome, descrição e o print implementado em MenuItem. Para que isso seja feito, foi

implementado o padrão Iterator. Ele busca todos os métodos print dos objetos do tipo

MenuComponent e executa.

Bloco 7. Implementação da classe MenuItem

A classe que interage com esta estrutura é Waitress e está apresentada no Bloco

8. Ela simplesmente executa o método print.

Bloco 8. Implementação da classe Waitress

public class Waitress{ MenuComponent allMenus; public Waitress(MenuComponent allMenus){ this.allMenus = allMenus; } public void printMenu(){ allMenus.print(); } }

public class MenuItem extends MenuComponent{ String name; String description; boolean vegetarian; double price; public MenuItem(String name, String description, boolean vegetarian, double price){ this.name = name; this.description = description; this.vegetarian = vegetarian; this.price = price; } public String getName(){ return name; } public String getDescription(){ return description; } public double getPrice(){ return price; } public boolean isVegetarian(){ return vegetarian; } public void print(){ System.out.print(" "+getName()); if(isVegetarian()){ System.out.print("(v)"); } System.out.println(", "+getPrice()); System.out.println(" -- "+getDescription()); } }

Page 27: Padrões de Projeto - Design Patterns

27

Bloco 9. Implementação da classe MenuItem

E por fim, a classe MenuTestDrive mostra um exemplo de como criar um menu

raiz e acrescentar seus menus, itens e as recursividades, caso necessário. Veja no Bloco

10. São criados os menus e também o menu raiz denominado allMenus, este objeto

representa toda a estrutura hierarquizada. Ao objeto allMenus, são adicionados outros

menus, sendo que estes menus serão adicionados itens e, no caso abaixo, o menu

dinerMenu possui um sub-menu dessertMenu, e que este possui um item nomeado

Apple Pie. Para exibir toda a estrutura é chamado o método print de Waitress.

public class MenuItem extends MenuComponent{ import java.util.ArrayList; import java.util.Iterator; public class Menu extends MenuComponent{ ArrayList<MenuComponent> menuComponents = new ArrayList<MenuComponent>(); String name; String description; public Menu(String name, String description){ this.name = name; this.description = description; } public void add(MenuComponent menuComponent){ menuComponents.add(menuComponent); } public void remove(MenuComponent menuComponent){ menuComponents.remove(menuComponent); } public MenuComponent getChild(int i){ return (MenuComponent)menuComponents.get(i); } public String getName(){ return name; } public String getDescription(){ return description; } public void print(){ System.out.print("\n"+getName()); System.out.println(", "+getDescription()); System.out.println("---------------------"); Iterator iterator = menuComponents.iterator(); while(iterator.hasNext()){ MenuComponent menuComponent = (MenuComponent)iterator.next(); menuComponent.print(); } } }

Page 28: Padrões de Projeto - Design Patterns

28

Bloco 10. Implementação da classe MenuTestDrive

Gamma et al.(2000) faz algumas considerações sobre este padrão.

• Hierarquias que consistem de objetos primitivos e compostos. Os

primitivos podem compor objetos mais complexos, os quais, por suas

vez, também podem compor outros objetos, e assim por diante

recursivamente. Sempre que o código esperar um objeto primitivo, ele

também poderá aceitar um objeto composto.

• Torna o cliente simples. Os clientes podem tratar estruturas compostas e

objetos individuas de maneira uniforme. Os clientes normalmente não

sabem (e não sabem deveriam se preocupar com isto) se estão tratando

com uma folha ou um componente composto. Isto simplifica o código a

ser escrito nas classes-cliente, porque evita o uso de comandos do tipo

CASE com os rótulos classes que definem composição.

• Torna mais fácil de acrescentar novas espécies de componentes. Novas

subclasses definidas, Composite ou Leaf, funcionam automaticamente

com as estruturas existentes e o código do cliente. Os clientes não

precisam ser alterados para tratar novas classes Component.

• Pode tornar o projeto excessivamente genérico. A desvantagem de

facilitar o acréscimo de novos componentes é que isso torna mais difícil

restringir os componentes de uma composição. Algumas vezes, é

public class MenuTestDrive{ public static void main(String args[]){ MenuComponent pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU","Breakfast"); MenuComponent dinerMenu = new Menu("DINER MENU","Lunch"); MenuComponent cafeMenu = new Menu("CAFÉ MENU","Dinner"); MenuComponent dessertMenu = new Menu("DESSERT MENU","Dessert of course!"); MenuComponent allMenus = new Menu("ALL MENUS","All menus combined"); allMenus.add(pancakeHouseMenu); allMenus.add(dinerMenu); allMenus.add(cafeMenu); dinerMenu.add(new MenuItem("Pasta","Spaghetti with Marinara Sauce, and a slice of sourdough bread",true,3.89)); dinerMenu.add(dessertMenu); dessertMenu.add(new MenuItem("Apple Pie","Apple pie with a flakey crust, topped with vanilla ice cream",true,1.59)); Waitress waitress = new Waitress(allMenus); waitress.printMenu(); } }

Page 29: Padrões de Projeto - Design Patterns

desejável que uma composição tenha somente certos componentes. Com

Composite, não pode confiar no sistema de tipos para garantir a

obediência a essas restrições. Ao invés disso, deve

teste em tempo d

4.3. DECORATOR

Este padrão, de forma dinâmica, agrega valores adicionais em qualquer objeto.

Fornece alternativa flexível no uso de subclasses para estender funcionalidades.

De acordo com Gamma

responsabilidades a objetos individuais dinamicamente e sem afetar outros objetos.

Outra característica é que essas responsabilidades pode

de alguma forma, desempenho ou estrutura.

Decorar objetos é muito comum quando não se quer te

subclasses. Por exemplo, havendo a necessidade de combinar responsabilidades entre

classes em um total de 6, i

diferentes.

Segundo Freeman (2004), q

subclasses, este comportament

Todas as subclasses devem herdar o mesmo comportamento. Contudo, por meio da

composição será possível esten

tempo de execução.

O padrão segue a seguinte

desejável que uma composição tenha somente certos componentes. Com

, não pode confiar no sistema de tipos para garantir a

obediência a essas restrições. Ao invés disso, deve-se usar verificações e

teste em tempo de execução.

DECORATOR

Este padrão, de forma dinâmica, agrega valores adicionais em qualquer objeto.

Fornece alternativa flexível no uso de subclasses para estender funcionalidades.

Gamma et al. (2000), o uso do Decorator acrescenta

bilidades a objetos individuais dinamicamente e sem afetar outros objetos.

Outra característica é que essas responsabilidades podem ser removidas sem prejudicar,

de alguma forma, desempenho ou estrutura.

Decorar objetos é muito comum quando não se quer ter uma explosão de

subclasses. Por exemplo, havendo a necessidade de combinar responsabilidades entre

classes em um total de 6, isso acarretará numa explosão de 40 combinações

Segundo Freeman (2004), quando há herança de um comportamento por meio de

subclasses, este comportamento é definido estaticamente no tempo de compilação.

Todas as subclasses devem herdar o mesmo comportamento. Contudo, por meio da

composição será possível estender o comportamento do objeto de forma dinâmica

seguinte estrutura:

Figura 6. Estrutura do padrão Decorator

29

desejável que uma composição tenha somente certos componentes. Com

, não pode confiar no sistema de tipos para garantir a

se usar verificações e

Este padrão, de forma dinâmica, agrega valores adicionais em qualquer objeto.

Fornece alternativa flexível no uso de subclasses para estender funcionalidades.

uso do Decorator acrescenta

bilidades a objetos individuais dinamicamente e sem afetar outros objetos.

ser removidas sem prejudicar,

r uma explosão de

subclasses. Por exemplo, havendo a necessidade de combinar responsabilidades entre 3

combinações de classes

amento por meio de

é definido estaticamente no tempo de compilação.

Todas as subclasses devem herdar o mesmo comportamento. Contudo, por meio da

forma dinâmica e em

Page 30: Padrões de Projeto - Design Patterns

A classe Component

responsabilidades acresce

define um objeto para o qual responsabilidades adicionais podem ser atribuídas; a classe

Decorator mantém uma referência para um objeto

que segue a interface de Component

ao componente.

4.3.1. Exemplo do Decorator

Freeman (2004) apresenta

mostrado na figura 5.

Beverage é uma classe abstrata de componente.

sozinha ou englobada por um decorador.

componentes concretos que

são um tipo de bebida. Esses objetos

CondimentDecorator “tem

CondimentDecorator tem uma variável de instância que co

bebida. Mocha, Whip e Soy

Beverage. Os decoradores podem adicionar novos métodos; no entanto, o novo

comportamento geralmente é adicionado fazendo cálculo antes e depois de um método

existente no componente. Eles precisam implementar não somente

getDescription().

Figura 7

Component define a interface para objetos que podem ter

ntadas aos mesmos dinamicamente; Concre

define um objeto para o qual responsabilidades adicionais podem ser atribuídas; a classe

mantém uma referência para um objeto Component e define uma interface

Component e ConcreteDecorator acrescenta responsabi

Exemplo do Decorator

apresenta um exemplo de aplicação do padrão decorator

é uma classe abstrata de componente. Cada bebida

por um decorador. Expresso, DarkRoast e HouseBlend

componentes concretos que estendem de Beverage no que caracteriza que essas classes

Esses objetos receberão dinamicamente novos comportamentos.

“tem-uma” (engloba) uma bebida, o que si

tem uma variável de instância que contém uma referência a uma

Soy são os decoradores e eles pode estender o estado de

es podem adicionar novos métodos; no entanto, o novo

mento geralmente é adicionado fazendo cálculo antes e depois de um método

Eles precisam implementar não somente cost()

7. Exemplo de implementação do padrão Decorator

30

define a interface para objetos que podem ter

ConcretComponent

define um objeto para o qual responsabilidades adicionais podem ser atribuídas; a classe

e define uma interface

acrescenta responsabilidades

padrão decorator

pode ser usada

HouseBlend são

no que caracteriza que essas classes

receberão dinamicamente novos comportamentos.

” (engloba) uma bebida, o que significa que o

ntém uma referência a uma

são os decoradores e eles pode estender o estado de

es podem adicionar novos métodos; no entanto, o novo

mento geralmente é adicionado fazendo cálculo antes e depois de um método

cost(), mas também

Page 31: Padrões de Projeto - Design Patterns

31

No bloco abaixo, segue o código para implementação da classe Beverage e suas subclasses.

Bloco 11. Implementação da classe Beverage

A classe CondimentDecorator simplesmente repassa as solicitações de

descrições para a bebida e suas subclasses estendem essa operação. O código é

mostrado no bloco abaixo.

public abstract class Beverage{ String description = "Unknown Beverage";

public String getDescription(){ return description; }

public abstract double cost(); }

public class Expresso extends Beverage{ public Expresso(){ description = "Expresso"; }

public double cost(){ return 1.99; } } public class HouseBlend extends Beverage{ public HouseBlend(){ description = "House Blend Coffee"; } public double cost(){ return 0.89; } }

public class DarkRoast extends Beverage{ public DarkRoast(){ description = "Dark Roast"; } public double cost(){ return 1.05; } }

Page 32: Padrões de Projeto - Design Patterns

32

Bloco 12. Implementação das classes dos condimentos

Com o padrão Decorator tornam-se fácil acrescentar os condimentos as bebidas

de forma dinâmica. Assim, não é preciso estabelecer que cada bebida possa ter apenas

um condimento, ou combinações de dois. Por exemplo, Expresso pode ter o condimento

Whip e também Whip com Soy ou até os três. Com uma pequena quantidade pode

public abstract class CondimentDecorator extends Beverage{ public abstract String getDescription(); } public class Soy extends CondimentDecorator{ Beverage beverage; public Soy(Beverage beverage){ this.beverage = beverage; } public String getDescription(){ return beverage.getDescription()+ ", Soy"; } public double cost(){ return 0.15 + beverage.cost(); } } public class Whip extends CondimentDecorator{ Beverage beverage; public Whip(Beverage beverage){ this.beverage = beverage; } public String getDescription(){ return beverage.getDescription()+", Whip"; } public double cost(){ return 0.10 + beverage.cost(); } } public class Mocha extends CondimentDecorator{ Beverage beverage; public Mocha(Beverage beverage){ this.beverage = beverage; } public String getDescription(){ return beverage.getDescription() + ", Mocha"; } public double cost(){ return 0.20 + beverage.cost(); } }

Page 33: Padrões de Projeto - Design Patterns

33

parecer fácil, mas se tivesse 20 condimentos para 10 tipos de bebidas ficaria difícil de

criar cada classe representando uma bebida com combinações de condimentos.

A atribuição de comportamentos em tempo de execução é apresentada no

seguinte bloco.

Bloco 13. Implementação da classe StarbuzzCoffee

No objeto beverage é simplesmente instanciado o objeto Expresso sem nenhum

condimento. Seu preço final será de R$ 1.99. Em beverage2, é instanciado o objeto

DarkRoast e é acrescentado 3 tipos de condimentos: Mocha, Soy e Whip. Para que

beverage2 contenha os condimentos é preciso instanciá-los e passar o tipo da bebida

como parâmetro, formando uma espécie de invólucro. Mocha envolve beverage2, assim

como Soy e Whip da mesma forma. A descrição da bebida retornará “Dark Roast,

Mocha, Soy, Whip” e o preço final (somando o custo da bebida mais os condimentos)

de R$ 1,50. De igual modo beverage3 recebe um condimento e a descrição e o preço

são alterados.

4.4. CHAIN OF RESPONSIBILITY

O Chain of Responsability (Cadeia de Responsabilidades) é um tipo de padrão

comportamental e, segundo Gamma et al. (2000), a intenção do padrão é evitar o

acoplamento do remetente de uma solicitação ao seu receptor, ao dar a mais de um

objeto a oportunidade de tratar a solicitação. Encadear os objetos receptores, passando a

solicitação ao longo da cadeia até que um objeto a trate. Na Figura 8 está demonstrada a

public class StarbuzzCoffee{ public static void main(String args[]){ Beverage beverage = new Expresso(); System.out.println(beverage.getDescription()+" R$"+beverage.cost()); Beverage beverage2 = new DarkRoast(); beverage2 = new Mocha(beverage2); beverage2 = new Soy(beverage2); beverage2 = new Whip(beverage2); System.out.println(beverage2.getDescription()+" R$"+beverage2.cost()); Beverage beverage3 = new HouseBlend(); beverage3 = new Mocha(beverage3); System.out.println(beverage3.getDescription()+" R$"+beverage3.cost()); } }

Page 34: Padrões de Projeto - Design Patterns

estrutura básica do padrão. A class

e opcionalmente implementa o elo (

solicitações pelas quais é responsável podendo também acessar seu sucessor e se o

ConcreteHandler pode tratar a

solicitação para o seu sucessor. Por fim, a classe

objeto ConcreteHandler da cadeia, (GAMMA et al., 2000).

O efeito que se dá quando um cliente emite uma solic

longo da cadeia até que um objeto

la.

Figura

4.4.1. Exemplo do Chain of Responsability

Para exemplificar, é abordado

uma operação efetuar pagamento entre os bancos.

Para iniciar, criar-

sistema, exibido no Bloco 14

Bloco

A classe BancoChain

responsabilidades. Ela possui um atributo que é o ident

referência para o próximo objeto. O método

e faz verifica se o próximo for nulo, então o próximo na corrente será o parâmetro; caso

public enum IDBancos { bancoA, bancoB, bancoC, bancoD }

drão. A class Handler define uma interface para tratar solicitações

e opcionalmente implementa o elo (link) ao sucessor. ConcreteHandle

solicitações pelas quais é responsável podendo também acessar seu sucessor e se o

pode tratar a solicitação, ele assim o faz; caso contrário, ele repassa a

solicitação para o seu sucessor. Por fim, a classe Client inicia a solicitação para um

da cadeia, (GAMMA et al., 2000).

O efeito que se dá quando um cliente emite uma solicitação, esta se propaga ao

longo da cadeia até que um objeto ConcreteHandler assuma a responsabilidade de tratá

Figura 8. Estrutura do Chain of Responsability

Exemplo do Chain of Responsability

Para exemplificar, é abordado um exemplo de Brizeno (2011) que implementa

uma operação efetuar pagamento entre os bancos.

-se uma enumeração que identificará os bancos utilizado no

14.

Bloco 14. Implementação da enumeração de IDBancos

BancoChain , exibida no Bloco 15, implementará a cadeia de

responsabilidades. Ela possui um atributo que é o identificador do banco e outro a

referência para o próximo objeto. O método setNext recebe uma nova instância da classe

e faz verifica se o próximo for nulo, então o próximo na corrente será o parâmetro; caso

bancoA, bancoB, bancoC, bancoD

34

define uma interface para tratar solicitações

ConcreteHandle trata de

solicitações pelas quais é responsável podendo também acessar seu sucessor e se o

solicitação, ele assim o faz; caso contrário, ele repassa a

inicia a solicitação para um

itação, esta se propaga ao

assuma a responsabilidade de tratá-

um exemplo de Brizeno (2011) que implementa

que identificará os bancos utilizado no

implementará a cadeia de

ificador do banco e outro a

recebe uma nova instância da classe

e faz verifica se o próximo for nulo, então o próximo na corrente será o parâmetro; caso

Page 35: Padrões de Projeto - Design Patterns

35

contrário, repassa esta responsabilidade para o próximo elemento. Então, a instância que

deve ser adicionada na corrente irá percorrer os elementos até chegar ao último.

O algoritmo de pagamento é verificar se o banco atual pode fazer o pagamento.

Para isto é utilizado o identificador do banco, que é comparado com o identificador

passado por parâmetro. Se o elemento atual puder responder a requisição é chamado o

método que vai efetuar o pagamento de fato. Este método é abstrato, e as subclasses

devem implementá-lo, com seu próprio mecanismo.

Se o elemento atual não puder responder, ele repassa a chamado ao próximo

elemento da lista. Antes disto é feita uma verificação, por questões de segurança, se este

próximo elemento realmente existe. Caso nenhum elemento possa responder, é

disparada uma exceção.

Bloco 15. Implementação da classe BancoChain

public enum IDBancos { public abstract class BancoChain { protected BancoChain next; protected IDBancos identificadorDoBanco; public BancoChain(IDBancos id) { next = null; identificadorDoBanco = id; } public void setNext(BancoChain forma) { if (next == null) { next = forma; } else { next.setNext(forma); } } public void efetuarPagamento(IDBancos id) throws Exception { if (podeEfetuarPagamento(id)) { efetuaPagamento(); } else { if (next == null) { throw new Exception("banco não cadastrado"); } next.efetuarPagamento(id); } } private boolean podeEfetuarPagamento(IDBancos id) { if (identificadorDoBanco == id) { return true; } return false; } protected abstract void efetuaPagamento(); }

Page 36: Padrões de Projeto - Design Patterns

36

Definida a estrutura da cadeia de responsabilidades, implementa-se um banco

concreto, que corresponde a uma chamada. O BancoA inicializa seu ID e, no método de

efetuar o pagamento, exibe no terminal que o pagamento foi efetuado. A implementação

dos ostros bancos segue este exemplo, exibida no Bloco 16 abaixo.

Bloco 16. Implementação do banco concreto

Sendo assim, cada banco chama seu método efetuarPagamento de acordo com a

cadeia de responsabilidades criada, de acordo com o bloco abaixo.

Bloco 17. Implemantação do padrão Chain of Responsability

O diagrama de classes deste exemplo mostrado na Figura 9.

public static void main(String[] args) { BancoChain bancos = new BancoA(); bancos.setNext(new BancoB()); bancos.setNext(new BancoC()); bancos.setNext(new BancoD()); try { bancos.efetuarPagamento(IDBancos.bancoC); bancos.efetuarPagamento(IDBancos.bancoD); bancos.efetuarPagamento(IDBancos.bancoA); bancos.efetuarPagamento(IDBancos.bancoB); } catch (Exception e) { e.printStackTrace(); } }

public class BancoA extends BancoChain { public BancoA() { super(IDBancos.bancoA); } @Override protected void efetuaPagamento() { System.out.println("Pagamento efetuado no banco A"); } }

Page 37: Padrões de Projeto - Design Patterns

Figura 9. Diagrama de classes do exemplo do padrão Chain of Responsability

Gamma et al. (2000), dest

• Acoplamento reduzido

qual o outro objeto que trata de uma solicitação. Um objeto tem que

saber somente que uma solicitação será tratada "apropriadamente"

Tanto o receptor como o remetente não conhecimento explícito um do

outro, e um objeto que está na cadeia não necessita conhecer a estrutura

da mesma.

• Flexibilidade adicional na atribuição de responsabilidades a objetos

Chain of Responsability dá uma flex

responsabilidades entre objetos. É possível acrescentar ou mudar

responsabilidades para o tratamento de uma solicitação pelo acréscimo

ou mudança da cadeia em tempo de execução. Pode

com subclasses pa

• A recepção não é garantida

receptor explícito, não há

pode sair pelo final da cadeia sem ter sido tratada. Uma solicitação

também pode não ser tratada quando a cadeia não está configurada

apropriadamente.

4.5. OBSERVER

O padrão Observer

Subscribe, define uma dependência um

. Diagrama de classes do exemplo do padrão Chain of Responsability

Gamma et al. (2000), destaca alguns benefícios e deficiências deste padrão.

Acoplamento reduzido: o padrão libera um objeto de ter que conhecer

qual o outro objeto que trata de uma solicitação. Um objeto tem que

saber somente que uma solicitação será tratada "apropriadamente"

anto o receptor como o remetente não conhecimento explícito um do

outro, e um objeto que está na cadeia não necessita conhecer a estrutura

Flexibilidade adicional na atribuição de responsabilidades a objetos

Chain of Responsability dá uma flexibilidade adicional na distribuição de

responsabilidades entre objetos. É possível acrescentar ou mudar

responsabilidades para o tratamento de uma solicitação pelo acréscimo

ou mudança da cadeia em tempo de execução. Pode-se combinar isto

com subclasses para especializar estaticamente os handlers

A recepção não é garantida. Uma vez que uma solicitação não tem um

receptor explícito, não há garantia de que ela será tratada

pode sair pelo final da cadeia sem ter sido tratada. Uma solicitação

também pode não ser tratada quando a cadeia não está configurada

apropriadamente.

O padrão Observer, também conhecido como Dependents ou Publish

efine uma dependência um-para-muitos entre objetos de forma que quando

37

. Diagrama de classes do exemplo do padrão Chain of Responsability

aca alguns benefícios e deficiências deste padrão.

um objeto de ter que conhecer

qual o outro objeto que trata de uma solicitação. Um objeto tem que

saber somente que uma solicitação será tratada "apropriadamente" .

anto o receptor como o remetente não conhecimento explícito um do

outro, e um objeto que está na cadeia não necessita conhecer a estrutura

Flexibilidade adicional na atribuição de responsabilidades a objetos. O

ibilidade adicional na distribuição de

responsabilidades entre objetos. É possível acrescentar ou mudar

responsabilidades para o tratamento de uma solicitação pelo acréscimo

se combinar isto

handlers.

. Uma vez que uma solicitação não tem um

de que ela será tratada - a solicitação

pode sair pelo final da cadeia sem ter sido tratada. Uma solicitação

também pode não ser tratada quando a cadeia não está configurada

, também conhecido como Dependents ou Publish-

muitos entre objetos de forma que quando

Page 38: Padrões de Projeto - Design Patterns

38

um objeto mudar de estado, todos os seus dependentes sejam notificados e atualizados

automaticamente (GAMMA et al., 2000).

No Observer quando um estado de um objeto é alterado, todos os seus

dependentes são notificados, e dependendo do tipo de notificação o observador também

pode ser atualizado com novos valores (FREEMAN et al., 2004). Observer desacopla

um objeto do conhecimento de que outros objetos dependem dele (ROCHA, 2003).

Existem algumas maneiras diferentes de se implementar o padrão Observer,

mas a maioria inclui as interfaces Subject e Observer. Um subject pode ter um número

qualquer de observadores dependentes, e todos os observadores são notificados quando

subject sofre uma mudança de estado, assim em resposta, cada observador inquirirá o

subject para sincronizar o seu estado com o estado do subject (GAMMA et al., 2000).

Esta iteração é o que GAMMA et al. (2000) chama de publish-subscribe, onde o subject

é o publicador de notificações e as envia sem ter que saber quem são os seus

observadores, lembrando que um número qualquer de observadores podem se inscrever

para receber essas notificações, nota-se então que existe uma relação entre um subject e

muitos observadores (1:N).

Como o sujeito é o único proprietário dos dados, os observadores dependem do

sujeito para alterá-los quando os dados são alterados, o que leva a um design orientado a

objetos mais simples do que permitir que muitos objetos controlem os mesmos dados

(FREEMAN et al., 2004).

Segundo Gamma et al. (2000), este padrão deve ser aplicado:

• Quando uma abstração tem dois aspectos, um dependente do outro.

Encapsulam-se esses aspectos separadamente para que assim permita-se

variá-los e reutizá-los independentemente.

• Quando uma mudança em um objeto exige mudanças em outros

objetos, e não sabe-se quantos objetos necessitam ser mudados.

• Quando não deseja-se que objetos sejam fortemente acoplados.

O padrão Observer fornece um design de objeto onde os sujeitos e os

observadores são levemente ligados, ou seja, os objetos podem interagir, mas sabem

muito pouco um do outro, o que trona mais fácil lidar com mudanças, já que minimizam

a interdependência entre os objetos (FREEMAN et al., 2004). Isso porque a única coisa

que o sujeito sabe sobre um observador é que ele implementa uma certa interface

Page 39: Padrões de Projeto - Design Patterns

(Observer), com isso podemos adicionar novos observadores a qualquer momento,

nunca precisaremos modificar o sujeito para adicionar novos tipos de observadores e

ainda podemos reutilizar sujeitos ou observadores independentemente uns dos outros

(FREEMAN et al., 2004).

Segundo o Rocha

padrões centrada no padrão Observer

o View é o Observer para o

pelo usuário e lê dados

encapsulando lógica de controle que afeta o

A figura 10 mostra a estrutura do padrão Observer.

Figura 10

Os participantes dessa estrutura são explicitados segundo Gamma

e Freeman et al. (2004):

• Subject –

objetos Observer pode observar um subject. Os objetos usam esta

interface para se regi

removidos.

• Observer –

deveriam ser notificados sobre mudanças em um subject. Todos os

observadores potenciais precisam implementar essa interface.

demos adicionar novos observadores a qualquer momento,

nunca precisaremos modificar o sujeito para adicionar novos tipos de observadores e

ainda podemos reutilizar sujeitos ou observadores independentemente uns dos outros

(2003) o padrão de arquitetura MVC é uma combinação de

padrões centrada no padrão Observer, onde o Model notifica o View sobre as alterações;

é o Observer para o Model e notifica o Controller sobre os eventos iniciados

pelo usuário e lê dados do Model; e o Controller é um Observer para o

encapsulando lógica de controle que afeta o Model e seleciona View.

mostra a estrutura do padrão Observer.

. Estrutura do padrão Observer (GAMMA et al, 2000).

Os participantes dessa estrutura são explicitados segundo Gamma

conhece os seus observadores. Um número qualquer de

objetos Observer pode observar um subject. Os objetos usam esta

interface para se registrarem como observadores e para serem

removidos.

– define uma interface de atualização para objetos que

deveriam ser notificados sobre mudanças em um subject. Todos os

observadores potenciais precisam implementar essa interface.

39

demos adicionar novos observadores a qualquer momento,

nunca precisaremos modificar o sujeito para adicionar novos tipos de observadores e

ainda podemos reutilizar sujeitos ou observadores independentemente uns dos outros

padrão de arquitetura MVC é uma combinação de

sobre as alterações;

sobre os eventos iniciados

é um Observer para o View,

Os participantes dessa estrutura são explicitados segundo Gamma et al. (2000)

conhece os seus observadores. Um número qualquer de

objetos Observer pode observar um subject. Os objetos usam esta

strarem como observadores e para serem

define uma interface de atualização para objetos que

deveriam ser notificados sobre mudanças em um subject. Todos os

observadores potenciais precisam implementar essa interface.

Page 40: Padrões de Projeto - Design Patterns

• ConcreteSubject

ConcreteObserver. Envia uma notificação para os seus observadores

quando seu estado muda.

• ConcreteObserver

que implemente a interface Observer. Mantém uma referênc

objeto ConcreteSubject, também armazena estados que deveriam

permanecer consistentes com os do Subject. Implementa a interface de

atualização de Observer, para manter seu estado consistente com o do

subject.

O ConcreteSubject notifica seus obser

mudança que poderia tornar inconsistente o estado deles com o seu próprio

et al., 2000).

A figura 11 apresenta um diagrama de sequencia de como as colaborações

acontecem entre um subject e dois observadores.

Figura 11. Diagrama de sequência entre um subject e dois observadores (GAMMA et al, 2000).

O objeto Observer na figura xxx que inicia a solicitação de mudança posterga

sua atualização até que consiga uma notificação do subject. Notify nã

chamada pelo subject, pode ser chamada por um observador ou por um outro tipo de

objeto (GAMMA et al., 2000).

As conseqüências (benefícios e deficiências) da utilização desse padrão

apontadas por Gamma et al. (2000) são: permite acrescentar obse

modificar o subject ou outros observadores; permite variar subjects e observadores de

forma independente; acoplamento abstrato entre Subject e

ConcreteSubject – armazena estados de interesse para objetos

ConcreteObserver. Envia uma notificação para os seus observadores

quando seu estado muda.

ConcreteObserver – os ConcreteObservers podem ser qualquer classe

que implemente a interface Observer. Mantém uma referênc

objeto ConcreteSubject, também armazena estados que deveriam

permanecer consistentes com os do Subject. Implementa a interface de

atualização de Observer, para manter seu estado consistente com o do

O ConcreteSubject notifica seus observadores sempre que ocorrer uma

mudança que poderia tornar inconsistente o estado deles com o seu próprio

apresenta um diagrama de sequencia de como as colaborações

acontecem entre um subject e dois observadores.

. Diagrama de sequência entre um subject e dois observadores (GAMMA et al, 2000).

O objeto Observer na figura xxx que inicia a solicitação de mudança posterga

sua atualização até que consiga uma notificação do subject. Notify nã

chamada pelo subject, pode ser chamada por um observador ou por um outro tipo de

., 2000).

As conseqüências (benefícios e deficiências) da utilização desse padrão

apontadas por Gamma et al. (2000) são: permite acrescentar obse

modificar o subject ou outros observadores; permite variar subjects e observadores de

forma independente; acoplamento abstrato entre Subject e Observer, e por não serem

40

armazena estados de interesse para objetos

ConcreteObserver. Envia uma notificação para os seus observadores

os ConcreteObservers podem ser qualquer classe

que implemente a interface Observer. Mantém uma referência para um

objeto ConcreteSubject, também armazena estados que deveriam

permanecer consistentes com os do Subject. Implementa a interface de

atualização de Observer, para manter seu estado consistente com o do

vadores sempre que ocorrer uma

mudança que poderia tornar inconsistente o estado deles com o seu próprio (GAMMA

apresenta um diagrama de sequencia de como as colaborações

. Diagrama de sequência entre um subject e dois observadores (GAMMA et al, 2000).

O objeto Observer na figura xxx que inicia a solicitação de mudança posterga

sua atualização até que consiga uma notificação do subject. Notify não é sempre

chamada pelo subject, pode ser chamada por um observador ou por um outro tipo de

As conseqüências (benefícios e deficiências) da utilização desse padrão

apontadas por Gamma et al. (2000) são: permite acrescentar observadores sem

modificar o subject ou outros observadores; permite variar subjects e observadores de

Observer, e por não serem

Page 41: Padrões de Projeto - Design Patterns

fortemente acoplados os mesmos podem pertencer a diferentes camadas de abs

suporte a comunicações broadcast sem especificar seu receptor; atualizações

inesperadas, pois como um observador não conhece a presença dos outros, eles podem

ser cegos para o custo global de mudança.

Os padrões relacionados são Mediator, encapsula

atualizações complexas, onde o ChangeManager atua como um mediador entre subjects

e observadores, e o Singleton onde o ChangeManager pode usar o Singleton para torná

lo único e globalmente acessível.

4.5.1. Exemplo de Observer

Para exemplificar o padrão Observer

(2004), incluindo a base da explicação sobre o exemplo

construção de uma estação meteorológica baseada na Internet, que deverá monitorar as

condições atuais do tempo (te

aplicativo que forneça as condições atuais, estatísticas meteorológicas e uma simples

previsão. A figura 12 apresenta o diagrama de classes que será utilizado no exemplo

Figura

fortemente acoplados os mesmos podem pertencer a diferentes camadas de abs

suporte a comunicações broadcast sem especificar seu receptor; atualizações

inesperadas, pois como um observador não conhece a presença dos outros, eles podem

ser cegos para o custo global de mudança.

Os padrões relacionados são Mediator, encapsulando a semântica de

atualizações complexas, onde o ChangeManager atua como um mediador entre subjects

e observadores, e o Singleton onde o ChangeManager pode usar o Singleton para torná

lo único e globalmente acessível.

Exemplo de Observer

car o padrão Observer utilizou-se um exemplo de

, incluindo a base da explicação sobre o exemplo. O exemplo baseia

construção de uma estação meteorológica baseada na Internet, que deverá monitorar as

condições atuais do tempo (temperatura, umidade e pressão). A ideia é criar

que forneça as condições atuais, estatísticas meteorológicas e uma simples

apresenta o diagrama de classes que será utilizado no exemplo

Figura 12. Diagrama de classes da estação meteorológica

41

fortemente acoplados os mesmos podem pertencer a diferentes camadas de abstração;

suporte a comunicações broadcast sem especificar seu receptor; atualizações

inesperadas, pois como um observador não conhece a presença dos outros, eles podem

ndo a semântica de

atualizações complexas, onde o ChangeManager atua como um mediador entre subjects

e observadores, e o Singleton onde o ChangeManager pode usar o Singleton para torná-

um exemplo de Freeman et al.

O exemplo baseia-se na

construção de uma estação meteorológica baseada na Internet, que deverá monitorar as

mperatura, umidade e pressão). A ideia é criar um

que forneça as condições atuais, estatísticas meteorológicas e uma simples

apresenta o diagrama de classes que será utilizado no exemplo.

Page 42: Padrões de Projeto - Design Patterns

42

De acordo com o diagrama de classe todos os componentes meteorológicos

implementam a interface Observer, o que dá a Subject uma interface comum com a qual

falar na hora de atualizar os observadores, e a interface DisplayElement deve ser

implementada por todos os elementos de exibição. As interfaces utilizadas são

mostradas no bloco 18.

Na interface Subject temos um método para registro e outro para exclusão de

um elemento, que utilizam um Observer como argumento. A interface Observer possue

o método update recebe os valores de estado do Subject quando uma medição muda.

Essa interface é implementada por todos os observadores. A interface DisplayElement

possui apenas o método display() que é chamado quando o elemento de exibição

precisar ser exibido.

A classe WeatherData monitora os dados vindos de Estação Meteorológica e

atualiza as exibições. O objeto WeatherData sabe como falar com a estação e obter os

dados atualizados de temperatura, umidade de pressão. O método

measurementsChanged() é chamado sempre que dados de medição estão disponíveis.

O bloco 19 mostra a classe WeatherData. Essa classe implementa a interface

Subject e adiciona uma lista para conter os Observers no método construtor. Como

implementamos Subject, os métodos registerObserver(), removeObserver() e

notifyObservers() devem ser aplicados, assim para adicionar um observador ele é

colocado no final da lista e para remover ele é retirado da lista. No notifyObservers() é

onde passamos para todas os observadores sobre o estado. O método

public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } public interface Observer { public void update(float temp, float umidade, float pressao); } public interface DisplayElement { public void display(); }

Bloco 18. Interfaces Subject, Observer e DisplayElement

Page 43: Padrões de Projeto - Design Patterns

43

measurementsChanged() notifica os Observers quando obtemos medições atualizadas da

Estação meteorológica. O método setMeasurements() foi utilizado para testar os

elementos de exibição.

Após isso, é hora de construir os elementos de exibição: exibição das

condições atuais, exibição das estatísticas e exibição da previsão. Todas as classes que

farão essas exibições devem implementar Observer e DisplayElement, nesse exemplo

public class WeatherData implements Subject{ private ArrayList observers; private float temperatura; private float umidade; private float pressao;

public WeatherData(){

observers = new ArrayList(); } @Override public void registerObserver(Observer o) {

observers.add(o); } @Override public void removeObserver(Observer o) {

int i = observers.indexOf(o); if (i >= 0){

observers.remove(i); }

} @Override public void notifyObservers() {

for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer) observers.get(i); observer.update(temperatura, umidade, pressao);

} } public void measurementsChanged() {

notifyObservers(); } public void setMeasurements(float temperatura, float umidade, float pressao){

this.temperatura = temperatura; this.umidade = umidade; this.pressao = pressao; measurementsChanged();

}

Bloco 19. Classe WeatherData

Page 44: Padrões de Projeto - Design Patterns

44

mostra-se apenas a implementação da exibição das condições atuais, pois as outras

seguem um formato parecido. O bloco 20 apresenta essa implementação.

A classe CurrentConditionsDisplay deve receber o objeto WeatherData (o

Subject) para registrar a exibição como um observador. O método display() imprimi

apenas a temperatura e a umidade mais recentes.

A classe de teste deverá criar o objeto WeatherData e as três exibições que

serão passadas para WeatherData, conforme bloco 21.

WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); //mostrar algumas estatísticas ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); //previsão de acordo com a pressão

public class CurrentConditionsDisplay implements Observer, DisplayElement { private float temperatura; private float umidade; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData){ this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void update(float temperatura, float umidade, float pressao) { this.temperatura = temperatura; this.umidade = umidade; display(); } @Override public void display() { System.out.println("Condições atuais: " + temperatura + "C graus e " + umidade + "% umidade"); } }

Bloco 20. Implemnetação das interfaces Observer e DisplayElement em CurrentConditionDisplay.

Bloco 21. Criação do objeto weatherData e as 3 exibições

Page 45: Padrões de Projeto - Design Patterns

45

Nesse exemplo criamos o um exemplo do padrão Observer, porém se

utilizarmos Java, há a opção de contar com o suporte interno ao padrão Observer dele,

assim tudo que teríamos que fazer é estender Observable e informá-lo quando notificar

os Observadores, pois a API faria o resto.

4.6. STRATEGY

O padrão Strategy, também conhecido como Policy, define uma família de

algoritmos, encapsula cada um deles e os torna intercambiáveis, assim a estratégia deixa

o algoritmo varias independentemente dos clientes que o utilizam (GAMMA et al.,

2000).

Strategy sugere que algoritmos parecidos sejam separados de quem os utiliza

(BRIZENO, 2011). Devemos separar o que muda do que fica igual (FREEMAN et al.,

2004). O padrão também apresenta facilidade para extensão das funcionalidades e

nenhuma outra parte do código precisa ser alterada. Nesse padrão as classes de

estratégia são chamadas de Comportamento e a classe que utiliza o comportamento é

chamada de Contexto, ou seja, para um determinado Contexto pode-se aplicar um

conjunto de comportamentos (BRIZENO, 2011).

Segundo Gamma et al. (2000), o padrão Strategy se aplica quando:

• Muitas classes relacionadas diferem somente no seu comportamento.

• Necessita-se de variantes de um algoritmo. As estratégias podem ser

usadas quando essas variantes são implementadas como uma hierarquia

de classes de algoritmos.

• Um algoritmo usa dados dos quais os clientes não deveriam ter

conhecimento.

• Uma classe define muitos comportamentos, e estes aparecem em suas

operações como múltiplos comandos condicionais da linguagem.

Strategy usa composição. Usar composição dá mais flexibilidade e permite

encapsular uma família de algoritmos em seu próprio conjunto de classes, além disso

permite alterar o comportamento no tempo de execução, desde o objeto com o qual

estiver compondo implemente a interface de comportamento certa (FREEMAN et al.,

2004). A composição é usada em outros padrões de projetos além do Strategy.

A figura 13 apresenta a estrutura do padrão Strategy.

Page 46: Padrões de Projeto - Design Patterns

Figura 13

Os participantes dessa estrutura são explicitados segundo Gamma

• Strategy –

suportados, e o Context usa esta interface para chamar o algoritmo

definido por uma ConcreteStrategy.

• ConcreteStrategy

Strategy.

• Context –

uma referência para um objeto Strategy. Pode definir uma interface que

permite a Strategy acessar seus dados.

Strategy e Context interagem para i

disso um contexto repassa solicitações dos seus clientes para sua estratégia (GAMMA

et al., 2000). A chave para aplicação do padrão Strategy é projetar, para a estratégia e

seu contexto, interfaces genéricas o bastant

(GAMMA et al., 2000).

Como consequências, entre benefícios e desvantagens, Gamma

aponta: famílias de algoritmos relacionadas; uma alternativa ao uso de subclasses;

eliminam comandos condicionais da l

escolha de implementações, fornecendo diferentes implementações do mesmo

comportamento; os clientes devem conhecer diferentes

podem ser expostos a detalhes e aspectos de implementação;

entre Strategy e Context pode ser um problema; aumento do número de objetos.

Quando outra pessoa está utilizando seu código ela pode escolher qualquer

comportamento para o contexto que ela deseja aplicar, o que

13. Estrutura do Padrão Strategy (GAMMA et al., 2000).

s dessa estrutura são explicitados segundo Gamma

– define uma interface comum para todos os algoritmos

suportados, e o Context usa esta interface para chamar o algoritmo

definido por uma ConcreteStrategy.

ConcreteStrategy – implementa o algoritmo usando a interface de

é configurado com um objeto ConcreteStrategy e mantém

uma referência para um objeto Strategy. Pode definir uma interface que

permite a Strategy acessar seus dados.

Strategy e Context interagem para implementar o algoritmo escolhido, além

disso um contexto repassa solicitações dos seus clientes para sua estratégia (GAMMA

A chave para aplicação do padrão Strategy é projetar, para a estratégia e

seu contexto, interfaces genéricas o bastante para suportar uma variedade de algoritmos

Como consequências, entre benefícios e desvantagens, Gamma

aponta: famílias de algoritmos relacionadas; uma alternativa ao uso de subclasses;

eliminam comandos condicionais da linguagem de programação; possibilidade de

escolha de implementações, fornecendo diferentes implementações do mesmo

comportamento; os clientes devem conhecer diferentes Strategies, assim os clientes

podem ser expostos a detalhes e aspectos de implementação; custo de comunicação

entre Strategy e Context pode ser um problema; aumento do número de objetos.

Quando outra pessoa está utilizando seu código ela pode escolher qualquer

contexto que ela deseja aplicar, o que pode ser visto como um

46

s dessa estrutura são explicitados segundo Gamma et al. (2000).

define uma interface comum para todos os algoritmos

suportados, e o Context usa esta interface para chamar o algoritmo

ta o algoritmo usando a interface de

é configurado com um objeto ConcreteStrategy e mantém

uma referência para um objeto Strategy. Pode definir uma interface que

mplementar o algoritmo escolhido, além

disso um contexto repassa solicitações dos seus clientes para sua estratégia (GAMMA

A chave para aplicação do padrão Strategy é projetar, para a estratégia e

e para suportar uma variedade de algoritmos

Como consequências, entre benefícios e desvantagens, Gamma et al (2000)

aponta: famílias de algoritmos relacionadas; uma alternativa ao uso de subclasses;

inguagem de programação; possibilidade de

escolha de implementações, fornecendo diferentes implementações do mesmo

, assim os clientes

custo de comunicação

entre Strategy e Context pode ser um problema; aumento do número de objetos.

Quando outra pessoa está utilizando seu código ela pode escolher qualquer

pode ser visto como um

Page 47: Padrões de Projeto - Design Patterns

47

potencial problema, já que o usuário deve conhecer bem a diferença entre as estratégias

para saber escolher qual se aplica melhor ao contexto dele (BRIZENO, 2011).

Como padrão relacionado temos o Flyweight, onde objetos Strategy geralmente

são bons flyweights (GAMMA et al., 2000).

4.6.1. Exemplo de padrão Strategy

Para exemplificar o padrão Strategy, utilizou-se um exemplo apresentado por

Brizeno (2011) com suas explicações, onde em uma empresa existe um conjunto de

cargos, para cada cargo existem regras de cálculo de imposto e determinada

porcentagem do salário deve ser retirada de acordo com o salário base do funcionário.

As regras são mostradas a seguir:

• O Desenvolvedor deve ter um imposto de 15% caso seu salário seja

maior que R$ 2000,00 e 10% caso contrário;

• O Gerente deve ter um imposto de 20% caso seu salário seja maior que

R$ 3500,00 e 15% caso contrário;

• O DBA deve ter um imposto de de 15% caso seu salário seja maior que

R$ 2000,00 e 10% caso contrário;

O padrão Strategy sugere que os métodos de cálculo de imposto sejam

separados do funcionário. Assim devemos encapsular todos os algoritmos da mesma

família, ou seja, a família que calcula salários com impostos deve ser separada, e para

encapsulá-las cria-se uma interface. O bloco 22 apresenta a criação da interface de

calculo do imposto.

Após definida a classe que encapsula os algoritmos, as estratégias concretas de

calculo do imposto devem ser definidas, assim como Brizeno (2011) definiremos

apenas uma das classes de cálculo, pois as outras 2 seguem o mesmo padrão. O Bloco

23 mostra a implementação do imposto de 20% ou 15%.

interface CalculaImposto { double calculaSalarioComImposto(Funcionario umFuncionario); }

Bloco 22. Interface CalculaImposto

Page 48: Padrões de Projeto - Design Patterns

48

Esta classe depende da classe CalculoImposto, assim como as outras duas

citadas, ou seja, ela utiliza um objeto CalculoImposto, assim de acordo com o cargo, em

tempo de execução, ocorrerá a instância da estratégia de cálculo correta.

No bloco 24, podemos observar a configuração da estratégia de cálculo no

método construtor, assim de acordo com a estratégia o construtor executa um dos cases.

Através do método calcularSalarioComImposto() efetua o calculo do salário com o

imposto.

public Funcionario(int cargo, double salarioBase) { this.salarioBase = salarioBase; switch (cargo) { case DESENVOLVEDOR: estrategiaDeCalculo = new CalculoImpostoQuinzeOuDez(); cargo = DESENVOLVEDOR; break; case DBA: estrategiaDeCalculo = new CalculoImpostoQuinzeOuDez(); cargo = DBA; break; case GERENTE: estrategiaDeCalculo = new CalculoImpostoVinteOuQuinze(); cargo = GERENTE; break; default: throw new RuntimeException("Cargo não encontrado :/"); } } public double calcularSalarioComImposto() { return estrategiaDeCalculo.calculaSalarioComImposto(this); }

public class CalculoImpostoVinteOuQuinze implements CalculaImposto { @Override public double calculaSalarioComImposto(Funcionario umFuncionario) { if (umFuncionario.getSalarioBase() > 3500) { return umFuncionario.getSalarioBase() * 0.8; } return umFuncionario.getSalarioBase() * 0.85; } }

Bloco 23. Implementaação do imposto de 20% ou 15%.

Bloco 24. Método construtor de Funcionario.

Page 49: Padrões de Projeto - Design Patterns

49

4.7. TEMPLATE METHOD

O Template Method é um padrão de projeto comportamental, e como um

padrão comportamental, ele tem que dar uma solução para que a interação entre objetos

tenha acoplamento fraco, aumentando a flexibilidade.

Segundo Gamma et al (2000), a intenção do Template Method é definir o

esqueleto de um algoritmo em uma operação, postergando alguns passos para as

subclasses. Template Method permite que subclasses redefinam certos passos de um

algoritmo sem mudar a estrutura do mesmo.

Quando em uma aplicação, dentro de um algoritmo, existem partes que sempre

devem ser executadas de uma determinada forma, mas outras partes deste algoritmo

podem variar, é recomendado o uso do Template Method. Fazendo com que a parte fixa

do algoritmo seja declarada, e dentro do algoritmo tenham chamadas para métodos que

podem ou devem ser redefinidos palas subclasses. Com isso as subclasses podem ser

trocadas a qualquer momento para poder variar o comportamento.

Segundo Gamma et al (2000), este fundamental para a reutilização de código.

É importante em bibliotecas de classe porque são meios para a fatoração dos

comportamentos comuns.

Um detalhe importante é que dentre os métodos que podem ser redefinidos

nesse padrão existem dois tipos, os chamados primitivos que são métodos abstratos que

devem ser obrigatoriamente redefinidos. E os chamados métodos gancho, que pode ou

não ser redefinido, que é utilizado quando queremos modificar um comportamento já

implementado ou deixar um ponto livre para que, quem desenvolve uma subclasse

possa colocar o que quiser naquele ponto.

4.7.1. Exemplo do Template Method

Para exemplificar o uso do padrão Template Method foi desenvolvido uma

estrutura de classes para realizar a autenticação de um usuário em um sistema.

Page 50: Padrões de Projeto - Design Patterns

Figura 14. Diagrama de cla

A figura 14 representa o diagrama de classes do exemplo. Nele contem a classe

usuário, que apenas armazena o login e senha. A classe AbstractLogin

método login que é o método template e as classes LoginPorArquivo e LoginPorBD

completam o método template com os trechos de código que variam dentro do

algoritmo de login.

Segue a explicação da implementação desse

classes.

public class Usuario { private String login; private String nome;

public Usuario(String login, this.login = login; this.nome = nome; }

public String getLogin() { return login; }

public void setLogin(String login) { this.login = login; }

public String getNome() { return nome; }

public void setNome(String this.nome = nome; } }

. Diagrama de classe do exemplo do padrão Template Method.

representa o diagrama de classes do exemplo. Nele contem a classe

usuário, que apenas armazena o login e senha. A classe AbstractLogin

método login que é o método template e as classes LoginPorArquivo e LoginPorBD

completam o método template com os trechos de código que variam dentro do

Segue a explicação da implementação desse, baseada nesse diagrama de

login, String nome) { = login;

getLogin() {

setLogin(String login) { = login;

getNome() {

String nome) {

Bloco 25. Classe Usuario.

50

.

representa o diagrama de classes do exemplo. Nele contem a classe

usuário, que apenas armazena o login e senha. A classe AbstractLogin que define o

método login que é o método template e as classes LoginPorArquivo e LoginPorBD

completam o método template com os trechos de código que variam dentro do

baseada nesse diagrama de

Page 51: Padrões de Projeto - Design Patterns

51

A classe usuário é uma classe simples com login e senha para exemplificar

uma representação de um usuário em um sistema.

A classe AbstractLogin, Bloco 26, declara o método login, que é um Template

Method. Este método é um algoritmo que começa chamando o método abstrato

doAutentica que é declarado na própria classe como método abstrato, isto quer dizer que

ele deve ser implementado em uma subclasse de AbstractLogin. Mais afrente no código

aparece a chamada para sucessoHook. O sucessoHook é um método chamado de

gancho, que é um ponto específico do algoritmo onde pode-se ou não ser sobrescrito.

Neste caso foi declarado em branco para ser sobrescrito caso o desenvolvedor queira

adicionar uma ação no sucesso do login.

O método doRegistrarSessao assim como o doAutentica é um método abstrato

que deve obrigatoriamente ser implementado nas subclasses. Já o falhaHook também é

um método gancho, onde pode adicionar uma ação quando o login falha.

Note que o método template login foi declarado como final, para que o

algoritmo não possa ser sobrescrito, com isso somente os pontos específicos dentro

desse algoritmo podem variar.

public abstract class AbstractLogin { public final boolean login(String login, String senha){ Usuario usuario = this.doAutentica(login, senha);

if(usuario != null){ this.sucessoHook(usuario); this.doRegistrarSessao(usuario); return true; }else{ this.falhaHook(usuario); return false; } }

public abstract Usuario doAutentica(String login, String senha); public abstract void doRegistrarSessao(Usuario usuario); public void sucessoHook(Usuario usuario){ } public void falhaHook(Usuario usuario){ } }

Bloco 26. Classe AbstractLogin

Page 52: Padrões de Projeto - Design Patterns

52

No bloco 27, exibe as classes LoginPorArquivo e LoginPorBD, que herdam da

classe AbstractLogin, por isso são obrigadas a implementar os métodos abstratos

doAutentica e doRegistrarSessao, cada um com sua variação. A classe

LoginPorArquivo substitui o método falhaHook adicionando uma ação quando o login

falha. A LoginPorBD implementa somente o sucessoHook executado quando o login é

efetuado com sucesso.

Um ponto que se deve ter atenção na hora de implementar é que tem que

declarar o método template de forma que ele não possa ser sobrescrito. Somente os

métodos primitivos e ganchos devem ser sobrescritos.

Outra coisa se deve fazer na hora de projetar um método template é não criar

muitas operações primitivas para serem sobrescritas. Pois pode se tornar tedioso para

um cliente implementar uma grande quantidade de operações.

public class LoginPorArquivo extends AbstractLogin{ public Usuario doAutentica(String login, String senha) { System.out.println("Acessando o arquivo de usuários"); if(login == "eduardo" && senha == "senha"){ return new Usuario(login, "Eduardo"); } return null; }

public void doRegistrarSessao(Usuario usuario){ System.out.println("Sessao criada para usuario"); }

public void falhaHook(Usuario usuario){ System.out.println("Ação da falha no login"); } } public class LoginPorBD extends AbstractLogin{ public Usuario doAutentica(String login, String senha) { System.out.println("Acessando banco de dados"); if(login == "eduardo" && senha == "senha" ){ return new Usuario(login, "Eduardo"); } return null; }

public void doRegistrarSessao(Usuario usuario){ System.out.println("Sessao criada para usuario"); }

public void sucessoHook(Usuario usuario){ System.out.println("Registrando login no log do sistema"); } }

Bloco 27. Classes LoginPorArquivo e LoginPorBD

Page 53: Padrões de Projeto - Design Patterns

4.8. VISITOR

Assim como o Template Method, o Visitor também é um padrão de projeto

comportamental.

A intenção do padrão Visitor

operação a ser executada nos elementos de uma estrutura de objetos. Visitor permite

definir uma nova operação sem mudar as classes dos elementos sobre os quais opera.

Pode-se usar o padrão Visitor, quando tempos uma estrutura de objetos, com

objetos em que suas interfaces diferem e você deseja executar operações sobre esses

objetos que dependem de suas cla

uma estrutura de objetos é compartilhada por várias aplicações e se quer definir

operações específicas para cada aplicação.

Aplicando esse padrão facilita a adição de novas operações. Quando se quer

adicionar novas operações sobre uma estrutura de objetos, basta criar uma nova

subclasse visitante. Outra vantagem do Visitor é que ele pode acumular estados de

acordo com que ele visita cada elemento da estrutura.

Um fator que tem que levar em conta na hora de de

padrão, é se a estrutura de objetos irá mudar com frequência. Caso isso possa acontecer,

é aconselhável que não seja usado, pois cada nova classe que é adicionada para a

estrutura, terá que ser criado um método abstrato em Visito

método em cada ConcreteVisitor. Ele é bom quando a quantidade de operações muda

com frequência e a estrutura de objetos muda pouco.

Figura

como o Template Method, o Visitor também é um padrão de projeto

A intenção do padrão Visitor segundo Gamma et al (2000) é representar uma

operação a ser executada nos elementos de uma estrutura de objetos. Visitor permite

peração sem mudar as classes dos elementos sobre os quais opera.

se usar o padrão Visitor, quando tempos uma estrutura de objetos, com

objetos em que suas interfaces diferem e você deseja executar operações sobre esses

objetos que dependem de suas classes concretas. Também pode ser utilizado quando

uma estrutura de objetos é compartilhada por várias aplicações e se quer definir

operações específicas para cada aplicação.

Aplicando esse padrão facilita a adição de novas operações. Quando se quer

r novas operações sobre uma estrutura de objetos, basta criar uma nova

utra vantagem do Visitor é que ele pode acumular estados de

acordo com que ele visita cada elemento da estrutura.

Um fator que tem que levar em conta na hora de decidir, sobre usar ou não o

padrão, é se a estrutura de objetos irá mudar com frequência. Caso isso possa acontecer,

é aconselhável que não seja usado, pois cada nova classe que é adicionada para a

estrutura, terá que ser criado um método abstrato em Visitor e ser implementado o

método em cada ConcreteVisitor. Ele é bom quando a quantidade de operações muda

com frequência e a estrutura de objetos muda pouco.

Figura 15. Diagrama de sequência do padrão Visitor

53

como o Template Method, o Visitor também é um padrão de projeto

é representar uma

operação a ser executada nos elementos de uma estrutura de objetos. Visitor permite

peração sem mudar as classes dos elementos sobre os quais opera.

se usar o padrão Visitor, quando tempos uma estrutura de objetos, com

objetos em que suas interfaces diferem e você deseja executar operações sobre esses

sses concretas. Também pode ser utilizado quando

uma estrutura de objetos é compartilhada por várias aplicações e se quer definir

Aplicando esse padrão facilita a adição de novas operações. Quando se quer

r novas operações sobre uma estrutura de objetos, basta criar uma nova

utra vantagem do Visitor é que ele pode acumular estados de

cidir, sobre usar ou não o

padrão, é se a estrutura de objetos irá mudar com frequência. Caso isso possa acontecer,

é aconselhável que não seja usado, pois cada nova classe que é adicionada para a

r e ser implementado o

método em cada ConcreteVisitor. Ele é bom quando a quantidade de operações muda

Page 54: Padrões de Projeto - Design Patterns

O diagrama de sequenci

padrão Visitor, executando uma operação sobre uma estrutura de objetos. Primeiro cria

um objeto ConcreteVisitor(aVisitor) e para cada classe da estrutura de

objetos(aConcreteElementA e aConcreteElementB),

accept passando o Visitor criado.

Para cada objeto que recebeu a chamada de método, ele se envia para o

ConcreteVisitor que realiza a operação em si, utilizando dados do ConcreteElement.

4.8.1. Exemplo de Visitor

Para exemplificar o padrão

programcreek.com (2013),

Visitor. Este exemplo cria uma estrutura de uma cidade com lugares que podem ser

visitados. Dependendo da necessidade essa visi

diferentes. A figura 16 apresenta o diagrama de classes que será utilizado no exemplo.

Figura

Segue abaixo o código da implementação do padrão de a

classes exibido.

sequencia exibido na figura 15 demonstra o funcionamento do

padrão Visitor, executando uma operação sobre uma estrutura de objetos. Primeiro cria

um objeto ConcreteVisitor(aVisitor) e para cada classe da estrutura de

objetos(aConcreteElementA e aConcreteElementB), na ObjectStruture chama o método

accept passando o Visitor criado.

Para cada objeto que recebeu a chamada de método, ele se envia para o

ConcreteVisitor que realiza a operação em si, utilizando dados do ConcreteElement.

Exemplo de Visitor

icar o padrão Visitor foi adaptado um exemplo de

, para que ficasse mais claro alguns conceitos do padrão

cria uma estrutura de uma cidade com lugares que podem ser

visitados. Dependendo da necessidade essa visita pode ser executada de formas

apresenta o diagrama de classes que será utilizado no exemplo.

Figura 16. Diagrama de classes do exemplo de Visitor.

Segue abaixo o código da implementação do padrão de acordo com o diagrama de

54

demonstra o funcionamento do

padrão Visitor, executando uma operação sobre uma estrutura de objetos. Primeiro cria

um objeto ConcreteVisitor(aVisitor) e para cada classe da estrutura de

na ObjectStruture chama o método

Para cada objeto que recebeu a chamada de método, ele se envia para o

ConcreteVisitor que realiza a operação em si, utilizando dados do ConcreteElement.

um exemplo de

para que ficasse mais claro alguns conceitos do padrão

cria uma estrutura de uma cidade com lugares que podem ser

ta pode ser executada de formas

apresenta o diagrama de classes que será utilizado no exemplo.

cordo com o diagrama de

Page 55: Padrões de Projeto - Design Patterns

55

Começamos pelo bloco 28 vê-se as interfaces Visitable e Visitor. A Visitable

define a assinatura de um método chamado accept. Uma classe deve implementar esse

método para que ela possa ser visitada por um Visitor. Já a interface Visitor declara,

que uma classe que tenha essa interface precisa implementar o método visit para City,

Museum e Park. O método visit é o método onde os comportamentos são executados.

A classe abstrata Place, vista no bloco 29 implementa a classe Visitable para

que possa ser visitado. Com isso ele tem que implementar o método accept, mas ele

declara esse método como abstrato para que a tarefa de implementar fique para suas

subclasses. A classe abstrata inclui o atributo nome e o método para seu acesso.

public class City implements Visitable{ ArrayList<Place> places = new ArrayList<Place>(); public void addPlace(Place lugar){ places.add(lugar); }

public void accept(Visitor visitor) { System.out.println("A Cidade está aceitando um visitor."); visitor.visit(this);

for(Visitable e: places){ e.accept(visitor); }

public abstract class Place implements Visitable{ private String nome;

protected Place(String nome){ this.nome = nome; }

public abstract void accept(Visitor visitor);

public String getNome(){ return this.nome; } }

public interface Visitable { public void accept(Visitor visitor); } public interface Visitor { public void visit(City city); public void visit(Museum museum); public void visit(Park park); }

Bloco 28. Interfaces Visitable e Visitor.

Bloco 29. Classe abstrata Place

Bloco 30. Implementação de Visitable na classe City.

Page 56: Padrões de Projeto - Design Patterns

56

O bloco 30 mostra como é a classe City, que é implementa Visitable. Ela tem

uma lista de lugares (Places) que são visitáveis. Ela como também é visitável, ela

implementa o método accept. Sendo que quando a cidade é visitada, ela chama a acão

visit do visitor passando seu próprio objeto e depois executa a operação accept em todos

os lugares de sua lista para que sejam visitados.

A Classe Museum e Park do bloco 31 herdam de Lugar, sendo ambos

visitáveis. Eles implementam o método accept para que sobre eles, possam ser

executados novos comportamentos somente passando visitantes diferentes como

parâmetro.

public class Museum extends Place {

public Museum(String nome){ super(nome);

} public void accept(Visitor visitor) {

System.out.println("O Museu está aceitando um visitor."); visitor.visit(this);

} public void seeThePaintings(){

System.out.println("O visitante viu as pinturas."); } } public class Park extends Place { public Park(String nome){

super(nome); } public void accept(Visitor visitor) {

System.out.println("O Parque está aceitando um visitor."); visitor.visit(this);

} public void enjoy(){

System.out.println("O visitante se divertiu no parque."); } }

Bloco 31. Classes Museum e Park.

Page 57: Padrões de Projeto - Design Patterns

57

A classe FirstTimeVisitor, bloco 32, realiza a interface Visitor. Com isso ele

adiciona uma operação nova para a estrutura de classes visitáveis. O FirstTimeVisitor

conhece as três classes concretas e executa a operação visit para cada uma de acordo

com suas estrutura. Ela armazena a quantidade de lugares que foram visitados, para que

possa ser consultado posteriormente.

Assim como o FirstTimeVisitor, o JobSeekerVisitor, bloco 33, também é um

visitante. Neste caso ele adiciona o comportamento de um visitante à procura de

emprego em uma cidade. Dado uma cidade com lugares ele visita cada lugar da cidade a

procura de emprego.

public class JobSeekerVisitor implements Visitor{ public void visit(City city) {

System.out.println("Estou procurando emprego na Cidade."); } public void visit(Museum museum) {

System.out.println("Estou procurando emprego no Museu " +museum.getNome()); } public void visit(Park park) {

System.out.println("Estou procurando emprego no Parque "+park.getNome()); } }

public class FirstTimeVisitor implements Visitor{ public int qtdeLugaresVisitados = 0;

public void visit(City city) { System.out.println("Estou visitando a Cidade."); }

public void visit(Museum museum) { this.qtdeLugaresVisitados++; System.out.println("Estou visitando o Museu " +museum.getNome()); museum.seeThePaintings(); }

public void visit(Park park) { this.qtdeLugaresVisitados++; System.out.println("Estou visitando o Parque " +park.getNome()); park.enjoy(); }

public int getQtdeLugaresVisitados(){ return this.qtdeLugaresVisitados; } }

Bloco 32. Classe FirstTimeVisitor.

Bloco 33. Classe JobSeekerVisitor.

Page 58: Padrões de Projeto - Design Patterns

58

O Visitor pode ser visto com frequência sendo utilizado junto ao padrão

Composite, usando um visitante para adicionar novas operações aos elementos da

estrutura.

Este padrão torna fácil a adição de novas operações, mas deve se ver se a

estrutura de objetos mudará com pouca frequência. Pois se ela for mudar com grande

frequência, não valerá a pena usar esse padrão devido ao custo de adicionar novas

classes na estrutura. Vale a pena quando a estrutura não muda muito, mas aparecem

novas operações com frequência.

5. PADRÕES NÃO GOF

GoF (Gang of Four) foi como ficou conhecido ao autores do livro Design

Patterns: Elements of Reusable Object-Oriented Software, principal referência deste

trabalho e da maioria de projetos sobre padrões de projeto. Neste capítulo daremos uma

visão geral de alguns padrões de projeto não criados por eles, porém todos relacionados

com o SOA Design Patterns, pois não foi encontrado outras referências significativas

para efeito de apresentação neste trabalho. Contudo outros padrões foram encontrados,

como EAA Patterns - Patterns of Enterprise Application Architecture (Padrões de

Arquitetura de Aplicações Corporativas) e Analysis Patterns (Padrões de Análise),

ambos de Martin Fowler, mas acreditamos estarem fora do contexto pois expressam

mais arquitetura e design de análise respectivamente. Apesar de SOA Patterns também

possuir um apelo arquitetônico, ele também possui uma base voltada para padrões de

design.

5.1. SOA DESIGN PATTERNS

SOA Patterns fornece orientação arquitetônica através de padrões e anti-

padrões, ele mostra como construir serviços SOA (Service Oriented Architecture) que

apresentem flexibilidade, disponibilidade e escalabilidade, e também possuem um vasto

conjunto de padrões (Rotem-GAL_OZ, 2012).

Um Padrão de Design SOA fornece uma solução comprovada para problemas

que normalmente surgem quando construímos um Serviço (ERL, 2009). Os Padrões de

Page 59: Padrões de Projeto - Design Patterns

59

Design SOA podem ser agrupados em: Padrões de Serviços, Padrões de Inventário de

Serviços, Padrões de Composições de Serviços, Padrões ESB (Enterprise Service Bus)

e Padrões de Orquestração. Cada um desses grupos possuem diversos padrões.

Como são muitos os padrões citaremos apenas alguns baseados na explicação

de Barbosa (2010) a título de conhecimento apenas.

No grupo “Serviços” podemos citar como exemplo o “Service Façade”, que

introduz componentes de “fachada” de modo a abstrair partes da arquitetura dos

Serviços preservando sua lógica principal evitando acoplamentos indesejados.

No grupo “Inventário de Serviços”, um dos mais importantes é o “Schema

Centralization” que evita redundância na representação de dados.

No grupo “Composição de Serviços”, um dos mais utilizados é o “Service

Agent” que são agentes capazes de processar rotinas a partir da interceptação de

mensagens.

O padrão “Asynchronous Queuing”, do grupo “ESB-Enterprise Service Bus” é

bastante importante, uma vez que ele resolve o problema de latência, que pode ocorrer

quando um Serviço Provedor não se encontra disponível para atender a uma chamada de

um Serviço Consumidor.

Dentre os padrões de “Orquestração” podemos citar o “State Repository” que

trata de persistir dados referentes a Informações de Estado por longos períodos, sem

consumir recursos dos Serviços.

6. CONCLUSÕES

6.1. CONTRIBUIÇÕES

Para desenvolvedores e projetistas, os padrões de projetos tornaram-se uma

ferramenta imprescindível no desenvolvimento de software. Os padrões aqui estudados,

são os mais conhecidos e usados por pessoas experientes na indústria do software

orientado a objetos.

Segundo Gamma et al. (2000), existem várias razões para usar os padrões.

Dentre elas, a manipulação dos padrões de projeto, fornece um vocabulário comum para

comunicar, documentar, e explorar alternativas de projeto. Os padrões tornam um

Page 60: Padrões de Projeto - Design Patterns

60

sistema menos complexo ao permitir falar sobre ele em um nível de abstração mais alto

do que aquele de uma notação de projeto ou uma linguagem de programação. Eleva o

nível no qual projeta e discute o projeto com outras pessoas.

Outra razão para usar padrões é o auxílio para documentação e para o

aprendizado. Pessoas que estão aprendendo programação orientada a objetos

frequentemente se queixam que os sistemas com os quais estão trabalhando usam

herança de forma confusa e inconsciente e que é fácil perder o fluxo de controle. Na

maioria das vezes, isso deve-se ao fato dessas pessoas não compreenderem os padrões

de projeto no sistema. O aprendizado dos padrões irá ajudar a compreender os sistemas

orientados a objetos existentes.

6.2. LIMITAÇÕES

O estudo dos padrões de projeto por iniciantes contribui para o uso de novos

algoritmos ou técnicas de programação orientada a objetos e fornece um método

rigoroso para projetar sistemas. Para programadores experientes em orientação a

objetos, padrões de projetos simplesmente documentam projetos existentes. De acordo

com Gamma et al. (2000), o autor reconhece a limitação de que seu livro é apenas um

catálogo de projetos, mas incentiva aos programadores experientes a pesquisarem e

estudarem e buscar novas soluções e resolver limitações de projetos existentes.

Page 61: Padrões de Projeto - Design Patterns

61

REFERÊNCIAS BIBLIOGRÁFICAS

BARBOSA, R. C. 2010. “Padrões de Design SOA”. Disponível em:

http://www.soamaster.com.br/component/content/article/38-artigos/82-padroes-design-soa.html.

Última consulta em 19/08/2013.

BERNADETE, D. H. C.; GONÇALVES, E. D.; CHAGAS, R. L. S.; “Aplicando a Engenharia

de Domínio para Construção de Um Framework de Emissão do Perfil Profissiográfico

Previdenciário”. Trabalho de Conclusão de Curso - CEFET (Centro Federal de Educação

Tecnológica) Campos. Campos dos Goytacazes, RJ, 2007.

BRIZENO, M. 2011. “Mãos na Massa: Chain of Responsability”. Disponível em:

http://brizeno.wordpress.com/category/padroes-de-projeto/chain-of-responsibility/. Última

consulta em 04/09/2013.

BRIZENO, M. 2011. “Mãos na Massa: Strategy”. Disponível em:

http://brizeno.wordpress.com/category/padroes-de-projeto/strategy/. Última consulta em

22/08/2013.

BRIZENO, M. 2011. “Mãos na Massa: Abstract Factory”. Disponível em:

http://brizeno.wordpress.com/category/padroes-de-projeto/abstract-factory/. Última consulta em

20/08/2013.

BRUSAMOLIN, V. 2004. “Manutenibilidade de Software”. Artigo publicado em Revista

Digital em 20/01/2004. Instituto Científico de Ensino Superior e Pesquisa (ICESP). Disponível

em: http://www.revdigonline.com/artigos_download/art_10.pdf. Última consulta em

11/08/2013.

BUSCHMANN, F., MEUNIER, R., ROHNERT, H., SOMMERLAD, P., & STAL, M. (1996).

“Pattern-oriented software architecture: A system of patterns”. Chichester, UK.

CAELUM. FJ-11: Java e Orientação a Objetos. Rio de Janeiro, RJ, Brasil, 2011. Curso de

Formação Java.

ERL, T. “SOA Design Patterns”. Editora Prentice Hall. 1ª Edição. New York. 2009.

Page 62: Padrões de Projeto - Design Patterns

62

FRAKES, W. B. e KANG, K. apud MOURA, A. M. M.; CARVALHO, J. S.; SILVA, R. J.

Abordagens de Reutilização de Software e sua Aplicação no Domínio de Arrecadação

Tributária Municipal. Monografia de Pós Graduação - CEFET (Centro Federal de Educação

Tecnológica) Campos. Campos dos Goytacazes, RJ, 2006.

FREEMAN, Eric & FREEMAN, Elisabeth. “Use a Cabeça! Padrões de Projetos”. 2ª edição

revisada. Tradução. Editora Alta Books, 2004.

GAMMA, E., HELM, R., JOHNSON, R., VLISSIDES, J. “Padrões de Projeto: Soluções

reutilizáveis de Software Orientado a Objetos”. Reimpressão 2008. Trad: Luíz A. M. Salgado.

Porto Alegre, editora Bookman, 2000.

KRUEGER, C. W. apud VASCONCELOS, A. P. V., Uma Abordagem de apoio à Criação de

Arquiteturas de Referência de Domínio baseada na Análise de Sistemas Legados. Tese de

D.Sc. - COPPE/UFRJ (Laboratório de Engenharia de Software / Universidade Federal do Rio de

Janeiro), Rio de Janeiro, RJ, Brasil 2007.

LEMOS, H. D. 2013. “Encapsulamento, Polimorfismo, Herança”. Disponível em:

http://www.devmedia.com.br/encapsulamento-polimorfismo-heranca-parte-01/12991. Última

consulta em 21/08/2013.

MACORATTI, J. C. 2002. “Padrões de Projeto – Design Patterns”. Disponível em:

http://www.macoratti.net/vb_pd1.htm. Última consulta em 12/08/2013.

MACORATTI, J. C. 2011. “Padrões de Projeto – Os 7 princípios Básicos do

Desenvolvimento de Software”. Disponível em: http://www.macoratti.net/11/05/sd_prnc1.htm.

Última consulta em 20/08/2013.

MACORATTI, J. C. 2011. “Herança x Composição”. Disponível em:

http://www.macoratti.net/11/05/oop_cph1.htm. Última consulta em 10/08/2013.

ODYSSEY, 2007; “Odyssey SDE”. Ambiente acadêmico de reutilização desenvolvido pela

COPPE/UFRJ – Laboratório de Engenharia de Software / Universidade Federal do Rio de

Janeiro. Disponível em: http://reuse.cos.ufrj.br/odyssey. Última consulta em 11/08/2013.

Page 63: Padrões de Projeto - Design Patterns

63

PEREIRA, V. C. “Design Patterns na Prática – Desvendando Mistérios”. Disponível em:

http://www.devmedia.com.br/desing-patterns-na-pratica-desvendando-misterios-parte-1/14713.

Última consulta em 19/08/2013.

PIGOSKI, T. M. apud BRUSAMOLIN, V. 2004. “Manutenibilidade de Software”. Artigo

publicado em Revista Digital em 20/01/2004. Instituto Científico de Ensino Superior e Pesquisa

(ICESP). Disponível em: http://www.revdigonline.com/artigos_download/art_10.pdf. Última

consulta em 11/08/2013.

PRESSMAN, R.S., Engenharia de Software, Trad., McGraw Hill, New York, 2006.

PROGRAMCREEK.COM. 2013. “Java Design Pattern: Visitor”. Disponível em:

http://www.programcreek.com/2011/05/visitor-design-pattern-example/. Última consulta em

22/08/2013.

ROCHA, H. 2003. Argo Navis Curso J930 – GoF Design Patterns em Java. Disponível em:

http://www.argonavis.com.br/cursos/java/j930/. Última consulta em 16/08/2013.

Rotem-GAL-OZ , A. 2012. “SOA Patterns”. Disponível em: http://arnon.me/soa-patterns/. Última consulta em 19/08/2013. UNIVERSIA. Curso 6170: Padrões de Projetos. Disponível em:

http://mit.universia.com.br/6/6.170/pdf/6.170_lecture-12.pdf. Última consulta em 19/08/2013.