Escolar Documentos
Profissional Documentos
Cultura Documentos
DE SOFTWARE
autor
LUIZ ANTONIO LEÃO LISBOA JUNIOR
1ª edição
SESES
rio de janeiro 2018
Conselho editorial roberto paes e gisele lima
Todos os direitos reservados. Nenhuma parte desta obra pode ser reproduzida ou transmitida
por quaisquer meios (eletrônico ou mecânico, incluindo fotocópia e gravação) ou arquivada em
qualquer sistema ou banco de dados sem permissão escrita da Editora. Copyright seses, 2018.
isbn: 978-85-5548-573-2.
Um breve histórico 19
Antipattern (Anti-Padrão) 24
Considerações 25
Aspectos técnicos 25
2. Padrões GoF 27
Famílias de padrões 28
Padrões de criação 29
Padrões estruturais 29
Padrões comportamentais 30
Abstract factory 30
Apresentação 30
Aplicabilidade 31
Estrutura 31
Descrição 32
Exemplo 32
Factory method 33
Apresentação 33
Aplicabilidade 34
Estrutura 34
Descrição 34
Exemplo 35
Builder 35
Apresentação 35
Aplicabilidade 35
Estrutura 36
Descrição 36
Exemplo 36
Prototype 37
Apresentação 37
Aplicabilidade 38
Estrutura 38
Descrição 38
Exemplo 38
Singleton 39
Apresentação 39
Aplicabilidade 40
Estrutura 40
Descrição 40
Exemplo 40
Adapter 41
Apresentação 41
Aplicabilidade 41
Estrutura 41
Descrição 42
Exemplo 42
Bridge 43
Apresentação 43
Aplicabilidade 43
Estrutura 43
Descrição 44
Exemplo 44
Composite 45
Apresentação 45
Aplicabilidade 45
Estrutura 45
Descrição 46
Exemplo 46
Decorator 47
Apresentação 47
Aplicabilidade 47
Estrutura 48
Descrição 48
Exemplo 48
Façade 49
Apresentação 49
Aplicabilidade 49
Estrutura 50
Descrição 50
Exemplo 50
Flyweight 51
Apresentação 51
Aplicabilidade 51
Estrutura 51
Descrição 52
Exemplo 52
Proxy 53
Apresentação 53
Aplicabilidade 53
Estrutura 54
Descrição 54
Exemplo 55
Chain of responsibility 55
Apresentação 55
Aplicabilidade 56
Estrutura 56
Descrição 56
Exemplo 56
Command 57
Apresentação 57
Aplicabilidade 57
Estrutura 58
Descrição 58
Exemplo 58
Interpreter 59
Apresentação 59
Aplicabilidade 59
Estrutura 60
Descrição 60
Exemplo 61
Iterator 61
Apresentação 61
Aplicabilidade 62
Descrição 62
Exemplo 63
Mediator 63
Apresentação 63
Aplicabilidade 64
Estrutura 64
Descrição 65
Exemplo 65
Memento 65
Apresentação 65
Aplicabilidade 66
Estrutura 66
Descrição 66
Exemplo 67
Observer 67
Apresentação 67
Aplicabilidade 68
Descrição 68
Exemplo 69
State 69
Apresentação 69
Aplicabilidade 70
Descrição 70
Exemplo 70
Strategy 72
Apresentação 72
Aplicabilidade 72
Descrição 72
Exemplo 73
TemplateMethod 73
Apresentação 73
Aplicabilidade 74
Estrutura 74
Descrição 74
Exemplo 75
Visitor 76
Apresentação 76
Aplicabilidade 76
Estrutura 77
Descrição 77
Exemplo 78
3. Padrões GRASP 81
Princípios básicos do catálogo de padrões GRASP 82
Padrões Básicos 83
Information expert (Especialista na informação); 83
Creator (Criador); 84
Low coupling (Baixo acoplamento) 85
High cohesion (Alta coesão) 88
Controller (Controlador) 89
Padrões avançados 91
Polymorphism (Polimorfismo) 91
Pure fabrication (Invenção pura) 92
Indirection (Indireção) 92
Protected variations (Variações protegidas) 93
4. Arquitetura em camadas 95
Conceito 96
Arquiteto de software 98
MVC 101
Visão (View) 102
Controlador (Controller) 102
Modelo (Model) 103
Vantagens 103
Desvantagens 103
SOA 105
Vantagens 106
Desvantagens 107
5. Aplicações práticas dos padrões GoF 109
Considerações sobre os exemplos 110
Builder 115
ConversorTexto.java 115
ConversorPDF.java 115
ConversorTeX.java 116
ConversorASCII.java 116
LeitorRTF.java 116
Cliente.java 117
Prototype 117
DocumentoPrototype.java 118
ASCIIPrototype.java 118
PDFPrototype.java 118
Cliente.jav 119
Singleton 119
Singleton.java 119
Cliente.java 120
Adapter 120
IImage.java 120
JpgImagem.java 120
JpgImagemAdapter.java 121
PngImagem.java 121
PngImagemAdapter.java 122
Cliente.java 122
Bridge 122
Janela Abstrata.java 123
IJanela.java 123
JanelaWindows.java 123
JanelaLinux.java 124
JanelaAviso.java 124
JanelaDialogo.java 124
Cliente.java 125
Composite 125
ArquivoComponent.java 125
ArquivoComposite.java 126
ArquivoVideo.java 127
Cliente.java 127
Decorator 127
Coquetel.java 128
CoquetelDecorator.java 128
Vodka.java 129
SucoLaranja.java 129
Cliente 129
Façade 130
Facade.java 130
Funcionario.java 130
Cargo.java 131
Setor.java 131
Cliente.java 132
Flyweight 132
ElementoFlyweight.java 132
Elemento.java 133
FlyweightFactory.java 133
Imagem.java 134
Ponto.java 134
Cliente.java 135
Proxy 136
Banco.java 136
BancoProxy.java 136
Cliente.java 137
Command 141
PagamentoCommand.java 141
Compra.java 141
PagamentoBoleto.java 143
PagamentoCartãoCredito.java 143
PagamentoCartãoDebito.java 143
Cliente.java 144
Interpreter 144
NumRomanoInterpreter.java 144
Contexto.java 146
UnidadeRomano.java 146
DezenaRomano.java 147
CentenaRomano.java 148
MilharRomano.java 148
Cliente.java 149
Iterator 150
IteradorCanais.java 150
CanaisAgregado.java 151
CanaisNoticia.java 151
Canal.java 152
Cliente.java 152
Mediator 153
Mediator.java 153
MensagemMediator.java 154
Colleague.java 154
AndroidColleague.java 155
IOSColleague.java 155
WindowsPhoneColleague.java 155
Cliente.java 156
Memento 156
TextoMemento.java 157
TextoCareTaker.java 157
Texto.java 158
Cliente.java 158
Observer 159
DadosObserver.java 159
Dados.java 159
DadosSubject.java 160
Barra Observer.java 160
PercentualObserver.java 161
TabelaObserver.java 162
Cliente.java 162
State 163
MarioState.java 163
Mario.java 163
Mario Pequeno.java 164
MarioGrande.java 164
MarioFogo.java 165
MarioPena.java 166
MarioMorto.java 167
Cliente.java 167
Strategy 168
StrategyCalculoImposto.java 168
CalculoImposto10_15.java 168
CalculoImposto15_20.java 169
Funcionario.java 169
Cliente.java 170
Visitor 175
Arvore Visitor.java 176
ArvoreBinaria.java 176
No.java 177
ExibirIdentadoVisitor.java 178
ExibirInOrderVisitor.java 178
Exibir Post Order Visitor.java 179
ExibirPreOrderVisitor.java 179
Prefácio
Prezados(as) alunos(as),
Essa obra tem como objetivo de ser um guia prático para a implementação
de padrões de projeto (design pattern) em softwares, tornando esse assunto mais
próximo da comunidade acadêmica. Em muitos momentos, a dificuldade em uti-
lizarmos tais práticas reside na carência de exemplos práticos. Com uma aborda-
gem destinada a solucionar problemas próximos do cotidiano das organizações, a
familiarização com os conceitos ocorrerá de forma mais natural.
Larman [1997] explica o seu entendimento sobre os padrões de projeto:
Novo padrão deveria ser considerado uma contradição se ele descrever uma
nova ideia. O próprio termo “padrão” sugere algo longamente repetido. A ideia de
padrões de projeto não é expressar novas ideias de projeto. Muito pelo contrário –
grandes padrões tentam codificar conhecimento, idiomas e princípios existentes
testados e verdadeiros. Quanto mais familiar, antigo e amplamente usado, melhor.
Ou seja, todo conhecimento acerca dos padrões catalogados, são fruto de pes-
quisas minuciosas em diversos projetos de software, para que pudessem servir de
subsídio paras as obras consagradas da literatura.
Com exemplos práticos, esse livro tem como objetivo ser um guia comple-
mentar para a implementação desses padrões, tornando o aprendizado desse tema
prazeroso e facilitado.
Bons estudos!
15
1
Fundamentos de
padrões de projetos
Fundamentos de padrões de projetos
Nesse capítulo serão abordadas as razões que motivaram a criação dos padrões
de projeto de software, um histórico sobre o surgimento do conceito de padrões
de projeto, como descrevê-los e utilizá-los.
Segundo Gamma et al [1995]
OBJETIVOS
• O que são padrões de projetos de software;
• Um breve histórico da sua criação;
• Como descrever um padrão;
• Os principais Padrões de Projetos existentes.
capítulo 1 • 18
Introdução aos padrões de projeto
Um breve histórico
capítulo 1 • 19
Towns, Buildings, Construction [Oxford University Press, 1977] e The Timeless Way
of Building [Oxford Unisersity Press, 1979]). As ideias apresentadas nesses livros
são aplicadas a diversas áreas de conhecimento, incluindo a de software.
Em 1987, na conferência OOPSLA (Object-Oriented Programming, Systems,
Languages&Applications), Ward Cunnhingham e Kent Beck publicaram um ar-
tigo (que pode ser encontrado no site de Cunnhingham: <http://c2.com/doc/
oopsla87.html>, abordando o uso dos conceitos criados por Alexander, para
desenvolver cinco padrões para design de interfaces com o usuário (UI Design),
iniciando o uso do conhecimento de padrões de projeto no contexto do projeto
de softwares.
No início dos anos 90, Erich Gamma, Richard Helm, Ralph Johnson e
John Vlissides iniciaram trabalhos na área de padronização de software, que
acabou por gerar um dos mais influentes livros de computação dessa década:
Design Patterns - Elements of Reusable Object-Oriented (em português, Padrões de
Projeto – Soluções Reutilizáveis de Software Orientado a Objetos). Publicado
em 1994, o livro popularizou a ideia de padrões. Esse livro é comumente conhe-
cido como Gang of Four ou GoF (Grupo dos Quatro), fazendo uma referência a
quantidade de autores da obra.
Nome
capítulo 1 • 20
em um nível mais alto de abstração. Ter um vocabulário para padrões permite-nos
conversar sobre eles com nossos colegas, em nossa documentação e até com nós
mesmos.
O nome torna mais fácil pensar sobre projetos e a comunicá-los, bem como
os custos e benefícios envolvidos, a outras pessoas. Encontrar bons nomes foi uma
das partes mais difíceis do desenvolvimento do nosso catálogo.
Problema
Define o momento em que o padrão deve ser aplicado. Ele explica o proble-
ma e seu contexto. Pode descrever problemas de projeto específicos, tais como
representar algoritmos como objetos. Pode descrever estruturas de classe ou objeto
sintomáticas de um projeto inflexível. Algumas vezes, o problema incluirá uma
lista de condições que devem ser satisfeitas para que faça sentido aplicar o padrão.
Solução
Consequências
capítulo 1 • 21
flexibilidade, a extensibilidade ou a portabilidade de um sistema. Relacionar essas
consequências explicitamente ajuda a compreendê-las e avaliá-las.
capítulo 1 • 22
Memento
Builder Proxy
saving state
of iteration
avoiding Adapter
hysteresis
defining
Iterator
traversais Bridge
creating
composites
enumerating
children composed
Command
using
adding
Decorator responsibilities Composite
to objects
sharing
composites adding
Visitor
operations
chaging skin definig
defining
versus guts Flyweight the chain
grammar
adding
operations
sharing
sharing
terminal Interpreter
strategies
symbols
sharing Chain of Responsibility
states
complex
Strategy State Mediator dependency Observer
management
defining
algorithm’s Template Method often uses
steps
configure factory
Prototype Factory Method
dynamically
implement using
single
Abstract Factory
instance
single
Singleton Facade
instance
PROPÓSITO
capítulo 1 • 23
Há também os conhecidos padrões GRASP (General Responsibility Assignment
Software Patterns / Principles), abordados no livro Applying UML and Patterns – An
Introduction to Object-Oriented Analysisand Designde Craig Larman. São eles:
• Padrões Básicos:
99 Information Expert (Especialista na Informação);
99 Creator (Criador);
99 High Cohesion (Alta Coesão);
99 Low Coupling (Baixo Acoplamento);
99 Controller (Controlador).
• Padrões Avançados:
99 Polymorphism (Polimorfismo);
99 Pure Fabrication (Invenção Pura);
99 Indirection (Indireção);
99 Protected Variations (Variações Protegidas).
Antipattern (Anti-Padrão)
capítulo 1 • 24
Algumas soluções que são habitualmente utilizadas em projetos de software
foram catalogadas nesse artigo, visando alertar a comunidade de desenvolvedores
sobre a ineficácia dessas práticas.
Considerações
Novo padrão deveria ser considerado uma contradição se ele descrever uma nova
idéia. O próprio termo “padrão” sugere algo longamente repetido. A idéia de padrões
de projeto não é expressar novas idéias de projeto. Muito pelo contrário – grandes
padrões tentam codificar conhecimento, idiomas e princípios existentes testados e ver-
dadeiros. Quanto mais familiar, antigo e amplamente usado, melhor.
Aspectos técnicos
capítulo 1 • 25
ATIVIDADES
01. Qual a importância dos padrões em um projeto de software?
02. Por que um padrão de projeto não descreve exatamente como a solução deve
ser implementada?
REFERÊNCIAS BIBLIOGRÁFICAS
GAMMA, ERICH et al. Design Patterns: Elements of Reusable Object-Oriented Software.
Addison-Wesley Professional. 1ª Edição. Estados Unidos da América: Addison-Wesley, 1995.
LARMAN, CRAIG. Utilizando UML e Padrões. 3ª Edição. Estados Unidos: Bookman, 2007.
FREEMAN,ELISABETH; FREEMAN,ERIC.Use a Cabeça! Padrões de Projetos (design Patterns).
2ª Edição. Estados Unidos: Alta Books, 2009.
KOENIG, ANDREW. Patterns and Antipatterns. Journal of Object-Oriented Programming, 1995; foi
re-impressoem: RISING, LINDA. The patterns handbook: techniques, strategies, and applications.
Cambridge, U.K.: Cambridge University Press, 1998.
capítulo 1 • 26
2
Padrões GoF
Padrões GoF
Será apresentado o catálogo de padrões de projeto dos autores Eric Gamma,
Richard Helm, Ralph Johnson e John Vlissedes, também conhecidos como GoF
(Gang of Four – Gangue/Grupo dos Quatro), que está publicado no livro, já re-
ferenciado, de 1995.
Esses padrões estão divididos pelas seguintes famílias de padrões: Padrões de
Criação ou de Construção, Padrões Estruturais e Padrões Comportamentais. Após
a apresentação das suas estruturas, serão apresentados exemplos práticos para a
implementação dessas soluções.
Cada padrão terá a seguinte estrutura:
• Apresentação;
• Aplicabilidade;
• Estrutura;
• Descrição;
• Exemplo.
OBJETIVOS
Ao fim dessa unidade, será possível compreender:
• O catálogo de padrões de projeto GoF;
• As famílias de padrões;
• A estrutura de cada padrão;
• Como aplicar os padrões a problemas cotidianos.
Famílias de padrões
capítulo 2 • 28
Padrões de criação
Padrões estruturais
se preocupam com a forma como classes e objetos são compostos para formar es-
truturas maiores. Os padrões estruturais de classes utilizam a herança para compor
interfaces ou implementações.
capítulo 2 • 29
interface para adaptar duas outras já existentes, assim uma nova classe é criada
para adaptar uma interface a outra. Os padrões com escopo de objeto utilizam
a composição de objetos para definir uma estrutura. Por exemplo, o padrão
Composite define uma estrutura de hierarquia para classes primitivas e compostas
em um objeto.
Padrões comportamentais
Abstract factory
Apresentação
capítulo 2 • 30
As classes implementando os elementos gráficos não podem ser definidas es-
taticamente no código. Precisamos de uma implementação diferente para cada
ambiente. Até em um mesmo ambiente, gostaríamos de dar a opção ao usuário de
implementar diferentes aparências (look-and-feels).
Podemos solucionar este problema definindo uma classe abstrata para cada
elemento gráfico e utilizando diferentes implementações para cada aparência ou
para cada ambiente.
Ao invés de criarmos as classes concretas com o operador new, utilizamos uma
Fábrica Abstrata para criar os objetos em tempo de execução.
O código cliente não sabe qual classe concreta será utilizada.
Aplicabilidade
Estrutura
AbstractFactory
CreateProductA() Client
CreateProductB() AbstractProductA
CreateProductA() CreateProductA()
AbstractProductB
CreateProductB() CreateProductB()
ProductB2 ProductB1
Figura 2.1 – Estrutura das classes do padrão Abstract Factory (GAMMA et al, 1995).
capítulo 2 • 31
Descrição
Exemplo
Janela
JanelaMotif JanelaQt
capítulo 2 • 32
Para a compreensão da estrutura, segue um resumo explicando cada classe:
• Gui Factory: Classe abstrata que estabelece as regras de criação de GUI –
Graphic User Interface.
• Motif Gui Factory: Classe concreta que implementa os componentes da
GUI Motif.
• Qt Gui Factory: Classe concreta que implementa os componentes da
GUI QT.
• Botao: Classe abstrata que representa todos os componentes Botao.
• Botao Motif: Classe concreta de construção de componentes Botao, usan-
do a GUI Motif.
• Botao Qt: Classe concreta de construção de componentes Botao, usando
a GUI Qt.
• Janela: Classe abstrata que representa todos os componentes Janela.
• Janela Motif: Classe concreta de construção de componentes Janela, usan-
do a GUI Motif.
• Janela Qt: Classe de concreta construção de componentes Janela, usando
a GUI Qt.
Factory method
Apresentação
Definir uma interface para criar um objeto, mas deixar as subclasses decidirem que
classe instanciar. O Factory Method permite adiar a instanciação para subclasses.
capítulo 2 • 33
Aplicabilidade
Recomenda-se a utilização desse padrão quando uma classe não pode anteci-
par ou conhecer a classe dos objetos que deve criar. Outra possibilidade é quando
uma classe quer que suas subclasses especifiquem os objetos que criam. Quando
classes delegam responsabilidade a alguma das várias subclasses ajudantes, e dese-
ja-se localizar qual é a subclasse ajudante acessada.
Estrutura
Creator
Product
FactoryMethod() Product = FactoryMethod()
AnOperation()
ConcreteProduct ConcreteCreator
Figura 2.3 – Estrutura das classes do padrão Factory Method (GAMMA et al, 1995).
Descrição
capítulo 2 • 34
Exemplo
Aplicação Documento
MinhaAplicação Meudocumento
criaDocumento() : Documento
Builder
Apresentação
Aplicabilidade
capítulo 2 • 35
computador básico. Poderiam ser criados métodos em classes aleatórias, que criam
os computadores, porém as diferentes lógicas de criação do computador ficariam
espalhadas pelo código. Essa solução provavelmente decairia em um anti-pattern
(anti-padrão), abordado no capítulo 1, situação essa que o padrão Builder resolve.
Estrutura
builder
Director Builder
Construct() BuildPart()
Figura 2.5 – Estrutura das classes do padrão Builder (GAMMA et al, 1995).
Descrição
Exemplo
capítulo 2 • 36
Builders
ConversorTexto
LeitorRTF
converterCaractere()
converterParagrafo() lerRTF()
converterFonte()
Neste exemplo, o método ler RTF (classe Leitor RTF) percorre uma lista com
os tokens encontrados no texto de entrada (formato RTF) e, para cada tipo de
token, chama um método do objeto de tipo Conversor Texto.
Dependendo do formato escolhido para o texto de destino, será escolhida
uma implementação da classe Conversor Texto: Conversor PDF, Conversor TeX
ou Conversor ASCII. Cada uma destas classes implementa os métodos de acordo
com as características do formato desejado. A classe Conversor ASCII não im-
plementa os métodos converte Paragrafo() e converte Fonte(), pois este formato
(ASCII) não possui elementos de estilo.
Prototype
Apresentação
Especificar os tipos de objetos a serem criados usando uma instância protótipo e criar
novos objetos pela cópia desse protótipo.
capítulo 2 • 37
Aplicabilidade
Em situações nas quais devem ser criadas instâncias de objetos a partir de hie-
rarquias de classes complexas e quando a classe de um objeto é conhecida somente
em tempo de execução são exemplos do uso deste padrão de projeto.
Estrutura
Operation() Clone()
ConcretePrototype1 ConcretePrototype2
p = prototype–>Clone()
Clone() Clone()
Descrição
Exemplo
capítulo 2 • 38
<<Interface>>
Cloneable
Cliente Documento
+ Clone() : Documento
ASCII PDF
Singleton
Apresentação
Garantir que uma classe tenha somente uma instância e fornecer um ponto global de
acesso para a mesma.
capítulo 2 • 39
Aplicabilidade
Estrutura
Singleton
return uniqueInstance
static Instance()
SingletonOperation()
GetSingletonData()
static uniqueInstance
singletonData
Figura 2.9 – Estrutura das classes do padrão Singleton (GAMMA et al, 1995).
Descrição
• Singleto: Define uma operação Instance que permite aos clientes acessar
em sua única instância. Instance é um método estático da classe. Pode ser respon-
sável pela criação da sua própria instância única.
Exemplo
Singleton
– singleton : Singleton
– Singleton()
+ getInstance() : Singleton
capítulo 2 • 40
Adapter
Apresentação
Aplicabilidade
Quando surgir a necessidade de usar uma classe existente, mas sua interface
não corresponder à interface de que o projeto precisa.
Quando quiser criar uma classe reutilizável que coopere com classes não-rela-
cionadas ou não-previstas, ou seja, classes que não necessariamente tenham inter-
faces compatíveis.
Ao utilizar adaptadores de objetos e for necessário usar várias subclasses exis-
tentes, porém, for impraticável adaptar essas interfaces criando subclasses para
cada uma. Um adaptador de objeto pode adaptar a interface da sua classe-mãe.
Estrutura
Request() SpecificRequest
adaptee
Adapter
Request() adaptee–>SpecifcRequest()
Figura 2.11 – Estrutura das classes do padrão Adapter (GAMMA et al, 1995).
capítulo 2 • 41
Descrição
Exemplo
Desenvolver um sistema que manipule imagens, e devem ser criadas APIs que
ofereçam essas funcionalidades. Será necessário ter um método para carregar a
imagem de um arquivo e outro para exibir a imagem na tela. Como pode o siste-
ma ser construído de tal forma que ele apresente uma interface independente de
qual API será utilizada? Para exemplificar,serão desenvolvidas classes de geração de
imagens baseadas nas bibliotecas OpenGL e GTK, como pode ser observado no
diagrama a seguir:
Gtklmagem OpenGLImagens
GtklmagemAdapter OpenGLImagensAdapter
<<interface>>
Imagem
Cliente
capítulo 2 • 42
Bridge
Apresentação
Segundo Gammaelat[1995]:
Desacoplar uma abstração da sua implementação, de modo que as duas possam variar
independentemente.
É uma solução muito parecida com o Adapter, porém, o Bridge fornece um ní-
vel de abstração maior, pois são separadas as implementações (Classes Concretas)
e as definições (Classes Abstratas), permitindo que cada um seja modificado de
forma independente.
Aplicabilidade
Estrutura
Cliente
ConcretelmplementorA ConcretelmplementorB
RefinedAbstraction Operationlmp() Operationlmp()
Figura 2.13 – Estrutura das classes do padrão Bridge (GAMMA et al, 1995).
capítulo 2 • 43
Descrição
Exemplo
<<interface>> JanelaAbstrata
IJanela
capítulo 2 • 44
Composite
Apresentação
A ideia do Composite é criar uma classe base que contém toda a interface necessária
para todos os elementos (objetos individuais) e criar um elemento especial que agrega
outros elementos (composições de objetos), como pode ser observado na figura.
Aplicabilidade
Estrutura
Client Component
Operation()
Add(Component)
Remove(Comlponent)
GetChild(int)
children
Leaf Composite
Operation() Operation()
Add(Component) forall g in children
Remove(Component) g.Operation();
GetChild(int)
Figura 2.15 – Estrutura das classes do padrão Composite (GAMMA et al, 1995).
capítulo 2 • 45
aComposite
Descrição
Exemplo
capítulo 2 • 46
Cliente ArquivoComponent
– nome : String
ArquivoVideo ArquivoComposite
– listaArquivos : ArrayList<ArquivoComponent>
Decorator
Apresentação
Aplicabilidade
capítulo 2 • 47
Estrutura
Component
Operation()
component
ConcreteComponent Decorator
Operation() Operation() component–>Operation()
ConcreteDecoratorA ConcreteDecoratorA
Operation() Operation() Decorator::Operation();
addedState AddedBehavion() AddedBehavior();
Figura 2.18 – Estrutura das classes do padrão Decorator (GAMMA et al, 1995).
Descrição
Exemplo
capítulo 2 • 48
Após a escolha da implementação do coquetel (Vodka, por exemplo), são es-
colhidas as implementações dos decoradores (Suco Laranja, Suco Tomate etc.) que
irão compor o coquetel.
Façade
Apresentação
Aplicabilidade
capítulo 2 • 49
Estrutura
Figura 2.20 – Estrutura das classes do padrão Façade (GAMMA et al, 1995).
Descrição
Exemplo
Funcionario
Cargo
capítulo 2 • 50
Flyweight
Apresentação
Aplicabilidade
Estrutura
if (flyweyght[key] exists) {
return existing flyweight;
} elise {
Create new flyweight;
add it to pool of flyweight;
return the new flyweight;
}
UnsharedConcreteFlyweight
ConcreteFlyweight
Operation(extrinsicState)
Operation(extrinsicState)
allState
IntrinsicState
Client
Figura 2.22 – Estrutura das classes do padrão Flyweight (GAMMA et al, 1995).
capítulo 2 • 51
aClient aClient
flyweight
pool
aFlyweighFactory aConcreteFlyweight aConcreteFlyweight
flyweigh intrinsicState intrinsicState
Figura 2.23 – Estrutura de compartilhamento dos objetos Flyweight (GAMMA et al, 1995).
Descrição
Exemplo
capítulo 2 • 52
Client FlyweightFactory
– Flyweights : List<ElementoFlyweight
+ getFlyweight(componente : EnumElementos) : void
ElementoFlyweight Ponto
Elemento Imagem
Proxy
Apresentação
Será utilizada uma classe substituta à classe original, para controlar o acessoàs
suas propriedades. A classe Proxygarantirá que ela possa realmente substituir a
classe original, através da compreensão doseu comportamento.
Aplicabilidade
Quando houver uma necessidade de uso mais sofisticado das classes, não me-
ramente fazendo referência aos seus objetos. Para isso é importante conhecer os
tipos de Proxy:
• Remote Proxies: São responsáveis pela codificação de uma solicitação e de
seus argumentos, bem como pelo envio da solicitação codificada para o objeto real
num espaço de endereçamento diferente;
capítulo 2 • 53
• Virtual Proxies: Podem manter informações adicionais sobre o objeto real,
de maneira que possam postergar o acesso ao mesmo.
• Protection Proxies: Verificam se quem chama tem as permissões de acesso
requeridas para executar uma consulta.
• Smart Reference: Este proxy é apenas um substituto simples para executar
ações adicionais quando o objeto é acessado, por exemplo para implementar me-
canismos de sincronização de acesso ao objeto original.
Estrutura
Client Subject
Request()
...
Figura 2.25 – Estrutura das classes do padrão Proxy (GAMMA et al, 1995).
Descrição
• Proxy: Mantém uma referência que permite ao proxy acessar o objeto real
(real subject). O proxy pode referenciar um Subject se as interfaces de Real Subject
e Subject forem as mesmas; fornece uma interface idêntica a de Subject, de modo
que o proxy possa substitur o objeto real (real subject); controla o acesso ao objeto
real e pode ser responsável pela sua criação e exclusão. Outras responsabilidades
dependem do tipo de proxy.
• Subject: Define uma interface comum para Real Subject e Proxy, de ma-
neira que um Proxy possa ser usado em qualquer lugar em que um Real Subject
é esperado.
• Real Subject: Define o objeto real que o proxy representa.
capítulo 2 • 54
Exemplo
Banco
Cliente
– totalClientes : int
– saldoClientes :double
+ getTotalClientes() : int
+ getSaldoClientes() : double
BancoProxy
– usuario : String
– senha : String
+ getTotalClientes() : int
+ getSaldoClientes() : double
+ checarPermissao : boolean
Chain of responsibility
Apresentação
capítulo 2 • 55
Aplicabilidade
Estrutura
successor
Client Handler
HandleRequest()
ConcreteHandler1 ConcreteHandler2
HandleRequest() HandleRequest()
Descrição
Exemplo
capítulo 2 • 56
ideia que surge é utilizar uma estrutura de decisão para verificar, dado um parâ-
metro, qual aforma de pagamento a ser utilizada na transação, porém será imple-
mentada a estrutura proposta pelo Chain of Responsability, que pode ser observada
no modelo a seguir.
Client PagamentoChain
Command
Apresentação
Aplicabilidade
Nesse padrão, os objetos podem ser parametrizados pela ação a ser executada,
como, por exemplo, uma opção de menu ou um botão em uma barra de ferra-
mentas. Opcionalmente, um comando pode especificar uma operação de desfazer
(undo), permitindo reverter os efeitos no próprio comando. Assim, a interface
Command deve declarar uma operação (método) – undo() – para realizar tal
operação.
capítulo 2 • 57
Estrutura
state
Figura 2.29 – Estrutura das classes do padrão Command (GAMMA et al, 1995).
Descrição
Exemplo
Uma loja que vende produtos e oferece várias formas de pagamento. Ao exe-
cutar uma compra, o sistema registra o seu valor e, de acordo com a forma de
pagamento selecionada, por exemplo, cartão de crédito, emite o valor total da
compra para o cartão de crédito do cliente, exibindo a quantidade de parcelas.
Outras formas de pagamento, como boleto bancário, teriam outras informações
relacionadas a compra, e assim por diante.
capítulo 2 • 58
Para este caso, vamos supor as seguintes classes para simplificar o exemplo:
Loja e Compra. As classes se relacionam, segundo o modelo a seguir:
<<interface>> PagamentoDebito
PagamentoCommand
PagamentoCredito
Cliente Loja
– qtdParcelas :int
+ executarCompra() : void + processarComprar(compra : Compra) : void
Compra PagamentoBoleto
Interpreter
Apresentação
Dada uma linguagem, definir uma representação para a sua gramática juntamente
com um interpretador que usa a representação para interpretar sentenças dessa
linguagem.
Aplicabilidade
capítulo 2 • 59
Estrutura
Context
AbstractExpression
Client
Interpret(Context)
TerminalExpression NonterminalExpression
Interpret(Context) Interpret(Context)
Figura 2.31 – Estrutura das classes do padrão Interpreter (GAMMA et al, 1995).
Descrição
capítulo 2 • 60
Exemplo
NumRomanoInterpreter
Iterator
Apresentação
capítulo 2 • 61
Este padrão de projeto oferece uma interface comum para que uma coleção
de objetos possa ser percorrida sem que a aplicação tome conhecimento de como
esses objetos estão agrupados.
Aplicabilidade
Aggregate Iterator
Client
CreateIterator() First()
Next()
IsDone()
Currentitem()
ConcreteAggregate
Concretelterator
CreateIterator()
Figura 2.33 – Estrutura das classes do padrão Iterator (GAMMA et al, 1995).
Descrição
capítulo 2 • 62
Exemplo
Cliente
CanaisAgregado IteradorCanais
+ primeiro() : void
+ proximo() : void
+ anterior() : void
+ ultimo() : void
CanaisNoticia Canal
Mediator
Apresentação
capítulo 2 • 63
O Mediator provê uma interface unificada a um conjunto de interfaces em
uma aplicação, onde um objeto promove a comunicação entre os vários objetos.
Desta forma, os objetos da aplicação deixam de manter relações entre si, reduzin-
do, assim, o acoplamento.
Aplicabilidade
A aplicabilidade para este padrão de projeto dá-se quando se quer separar a co-
municação que vários objetos têm entre si através de uma interface bem definida,
diminuindo, assim, suas interdependências.
Estrutura
mediator
Mediator Colleague
Figura 2.35 – Estrutura das classes do padrão Mediator (GAMMA et al, 1995).
aColleague
mediator
aColleague aColleague
mediator mediator
aConcreteMediator
aColleague aColleague
mediator mediator
Figura 2.36 – Estrutura comum de objetos no padrão Mediator (GAMMA et al, 1995).
capítulo 2 • 64
Descrição
Exemplo
Cliente
Colleague <<interface>>
Mediator
Memento
Apresentação
capítulo 2 • 65
Esse padrão oferece uma maneira simples de salvar estados internos de um
objeto. Basta salvar todas as informações necessárias em uma classe de armazena-
mento de estados(Memento) e mais tarde recuperá-las.
Aplicabilidade
Estrutura
memento
Originator Memento Caretaker
SetMemento(Memento m) GetState()
CreateMemento() SetState()
state state
Figura 2.38 – Estrutura das classes do padrão Memento (GAMMA et al, 1995).
Descrição
capítulo 2 • 66
• Originator: Cria um memento contendo um instantâneo do seu estado
interno corrente; usa o memento para restaurar o seu estado interno.
• Caretaker: É responsável pela custódia do memento; nunca opera ou exa-
mina os conteúdos de um memento.
Exemplo
Texto TextoCaretaker
TextoMemento
Observer
Apresentação
Esse padrão tem como objetivo definir uma estrutura onde um objeto, que
esteja relacionado a vários outros, crie uma situação de observância, ou seja, quan-
do esse objeto muda de estado, todos os seus dependentes serão notificados sobre
essa mudança.
capítulo 2 • 67
Aplicabilidade
Subject Obsever
observers
Attach(Observer) Update()
Detach(Observer) for all o in observers {
Notify() o–>Update()
}
ConcreteSubject ConcreteObserver
subject observerState=
GetState() Update()
SetState() subject–>GetState()
observerState
subjectState return subjectState
Figura 2.40 – Estrutura das classes do padrão Observer (GAMMA et al, 1995).
Descrição
capítulo 2 • 68
Exemplo
DadosObserver
Cliente DadosSubject
State
Apresentação
Permite a um objeto alterar seu comportamento quando o seu estado interno muda. O
objeto parecerá ter mudado sua classe.
capítulo 2 • 69
Aplicabilidade
state
Context State
Request() Handle()
state–>Handle()
ConcreteStateA ConcreteStateB
Handle() Handle()
Figura 2.42 – Estrutura das classes do padrão State (GAMMA et al, 1995).
Descrição
Exemplo
capítulo 2 • 70
pequeno, e ficar com a habilidade de soltar bolas de fogo, entre outras situações.
Adiante segue o diagrama de transição de estados que aborda o esquema de trocas:
pegarPena
pegarFlor
sofrerDano
pegarPena
sofrerDano
sofrerDano Capa Fogo
pegarFlor
Morto
sofrerDano
pegarPena
pegarFlor
capítulo 2 • 71
Strategy
Apresentação
Definir uma família de algoritmos, encapsular cada uma delas e torná-las intercam-
biáveis. Strategy permite que o algoritmo varie independentemente dos clientes que
o utilizam.
Aplicabilidade
strategy
Context Strategy
ContextInterface() Algorithminterface
Figura 2.45 – Estrutura das classes do padrão Strategy (GAMMA et al, 1995).
Descrição
capítulo 2 • 72
• Concrete Strategy: Implementa o algoritmo usando a interface de Strategy.
• Context: É configurado com um objeto Concrete Strategy; mantém uma
referência para um objeto Strategy; pode definir uma interface que permite a
Strategy acessar seus dados.
Exemplo
CalculoImposto10_15 CalculoImposto15_20
TemplateMethod
Apresentação
capítulo 2 • 73
Tem a função de generalizar um processo, em um nível mais genérico, em um
conjunto de passos, permitindo que etapas comuns sejam implementadas e que
etapas específicas tenham suas implementações realizadas por classes descenden-
tes. Em outras palavras, o Template Method permite que subclasses de uma classe
comum possam variar partes de um algoritmo mais geral.
Aplicabilidade
Estrutura
AbstractClass ...
PrimitiveOperation1()
TemplateMethod() ...
PrimitiveOperation1() PrimitiveOperation2()
PrimitiveOperation2() ...
ConcreteClass
PrimitiveOperation1()
PrimitiveOperation2()
Figura 2.47 – Estrutura das classes do padrão Template Method (GAMMA et al, 1995).
Descrição
capítulo 2 • 74
operações primitivas, bem como operações definidas em Abstract Class ou ainda
outros objetos.
• Concrete Class: Implementa as operações primitivas para executarem os
passos específicos do algoritmo da subclasse.
Exemplo
Playlist
+ addMusical()
Musica
Client <<enum>>
EnumModoReproducao – nome : String
– autor : String
– ano : int
– avaliacao : int
OrdenadorTemplate
+ ordenarMusical() : ArrayList<Musica>
+ isPrimeiro() : boolean
capítulo 2 • 75
Visitor
Apresentação
Representar uma operação a ser executada nos elementos de uma estrutura de ob-
jetos. Visitor permite definir uma nova operação sem mudar as classes dos elementos
sobre os quais opera.
Pela descrição, é possível ver como o padrão deve ser usado. A sua ideia é
separar as operações que serão executadas em determinada estrutura de sua re-
presentação. Assim, incluir ou remover operações não terá nenhum efeito sobre a
interface da estrutura, permitindo que o resto do sistema funcione sem depender
de operações específicas.
Aplicabilidade
Este padrão de projeto pode ser utilizado quando uma estrutura de objetos
contém muitas classes com interfaces diferentes e se deseja executar operações
distintas ou sem relação entre si.
Isto evita a “poluição” de código e mantém códigos relacionados em uma
única classe.
Além disto, normalmente, a frequência de mudanças nas estruturas de objetos
é pequena, enquanto que novas operações podem ser acrescentadas a medida que
os requisitos se modificam.
capítulo 2 • 76
Estrutura
Client Visitor
VisitConcreteElementA(ConcreteElementA)
VisitConcreteElementB(ConcreteElementB
ConcreteVisitor1 ConcreteVisitor2
VisitConcreteElementA(ConcreteElementA) VisitConcreteElementA(ConcreteElementA)
VisitConcreteElementB(ConcreteElementB VisitConcreteElementB(ConcreteElementB
ObjectStructure Element
Accept(Visor)
ConcreteElementA ConcreteElementA
Accept(Visitor v) Accept(Visitor v)
OperationA() OperationB()
v–>VisitConcreteElementA(this) v–>VisitConcreteElementB(this)
Figura 2.49 – Estrutura das classes do padrão Visitor (GAMMA et al, 1995).
Descrição
• Visitor: Declara uma operação Visit para cada classe Concrete Element na
estrutura do objeto. O nome e a assinatura da operação identifica a classe que
envia a solicitação Visit ao visitante. Isso permite ao visitante determinar a classe
concreta do elemento que está sendo visitado. Então, o visitante pode acessar o
elemento diretamente através da sua interface específica.
• Concrete Visitor: Implementa cada operação declarada por Visitor. Cada
operação implementa um fragmento do algoritmo definido para a correspondente
classe de objeto na estrutura. Concrete Visitor fornece o contexto para o algoritmo
e armazena o seu estado local. Esse estado frequentemente acumula resultados
durante o percurso da estrutura.
• Element: Define uma operação Accept que aceita um visitante como um
argumento.
capítulo 2 • 77
• Concrete Element: Implementa uma operação Accept que aceita um visi-
tante como um argumento.
• Object Structure: Pode enumerar seus elementos; pode fornecer uma in-
terface de alto nível para permitir ao visitante visitar seus elementos; pode ser uma
composição (ver o padrão Composite), ou uma coleção, tal como uma lista ou
um conjunto.
Exemplo
Client ArvoreBinaria No
+ <<create>> ArvoreBinaria(chaveRaiz : int) : void – chave : int
+ inserir(chave : int) : void – esquerdo : No
+ remover(chave : int) : void – direito : No
+ buscar(chave : int) : void
+ inserir(chave : int, no : No) : void
+ aceitarVisitante(visitor : ArvoreVisitor) void
Element
Accept(Visor)
+ visitar(no : No) : void + visitar(no : No) : void + visitar(no : No) : void + visitar(no : No) : void
+ visitar(no : No, qtdEspacos : int) : void
capítulo 2 • 78
ATIVIDADES
01. Qual o objetivo dos padrões Comportamentais, segundo o catálogo GOF?
04. Em uma janela pode-se adicionar objetos como barras de rolagem, caixas de texto, la-
bels etc. Pode-se criar uma classe Auxiliar que será estendida pelos decoradores que irão in-
serir propriedades na janela. Qual o padrão de projetos que possibilita essa implementação?
05. Dois dos principais padrões utilizados atualmente são descritos a seguir:
I. Visa garantir que uma classe só tenha uma única instância e prover um ponto de acesso
global a ela.
II. Visa definir uma dependência um-para-muitos entre objetos para que quando um objeto
mudar de estado os seus dependentes sejam notificados e atualizados automaticamente.
Quais os padrões de projeto descritos?
REFERÊNCIAS BIBLIOGRÁFICAS
GAMMA, ERICH et al. Design Patterns: Elements of Reusable Object-Oriented Software.
Addison-Wesley Professional. 1ª Edição. Estados Unidos da América: Addison-Wesley, 1995.
LARMAN, CRAIG. Utilizando UML e Padrões. 3ª Edição. Estados Unidos da América: Prentice Hall,
2007.
FREEMAN,ELISABETH; FREEMAN,ERIC.Use a Cabeça! Padrões de Projetos (design Patterns).
2ª Edição. Estados Unidos da América: Alta Books, 2009.
capítulo 2 • 79
capítulo 2 • 80
3
Padrões GRASP
Padrões GRASP
Craig Larman, através do livro “Applying UML and Patterns”[1997], publicou
o catálogo de padrões de projeto GRASP (General Responsability Assignment
Software Patterns – Padrões de Software de Atribuição de Responsabilidade Geral),
De acordo comLarman[1997], sobre os padrões GRASP:
OBJETIVOS
• Os princípios sobre os padrões GRASP;
• Os padrões GRASP básicos e avançados;
• O detalhamento do problema e da solução proposta por cada padrão.
ESTUDO DE CASO
Um sistema de e-com-
Pedido ItemPedido –> Produto
merce, que tem a repre-
– descrição : String
sentação básica do modelo – dataPedido : Date – preço : double
na figura a seguir, será o
ItemPedido
ponto de partida para o
estudo de caso dos pa- – quantidade : int
capítulo 3 • 82
Padrões Básicos
Problema:
Solução:
Exemplo:
Especialista em Pedido
capítulo 3 • 83
Creator (Criador);
Problema:
Quem deve ser responsável por criar uma nova instância de uma classe?
Solução:
Exemplo:
Pedido Produto
ItemPedido –>
– descrição : String
– dataPedido : Date
– preço : double
+ totalPedido() : double
+ adicionarItemVenda(qtd : int) : void ItemPedido
– quantidade : int
Adicionar o método
adicionarItemVenda() + subTotal() : double
capítulo 3 • 84
Sobre o acoplamento de classes
Classes que, por natureza, são genéricas e que têm alta probabilidade de reuti-
lização deveriam ter acoplamento baixo.
O caso extremo do baixo acoplamento é o não acoplamento: contraria o prin-
cípio da orientação a objetos: objetos conectados, trocando mensagens entre si.
O acoplamento alto não é o problema em si. O problema é o acoplamento a
classes que, de alguma forma são instáveis: sua interface, sua implementação ou
sua mera presença.
Problema:
Solução:
Exemplo:
capítulo 3 • 85
Segundo o padrão Creator, o módulo de cobrança do e-commerce deve criar
um objeto Pagamento e repassá-lo ao Pedido, como pode ser visto no diagrama de
comunicação a seguir:
1: efetuarPagamento() 2: criar()
3: efetuarPagamento(p:Pagamento) : void
: Pedido
Figura 3.4 –
O problema desse modelo é que foi gerado um acoplamento entre três classes.
Em busca do baixo acoplamento, o modelo deve ser refatorado, ignorando o
que foi estabelecido, nesse caso, pelo padrão Creator.
1: efetuarPagamento() 2: efetuarPagamento()
<<actor>>
Cobrança : Pedido
: Cliente
2.1: Criar
p : Pagamento
Figura 3.5 –
• Acoplamento de Controle:
– Passar flags de controle entre objetos de forma que um objeto controle as
etapas de processamento de outro objeto;
capítulo 3 • 86
– Ocorrência comum:
• Objeto A manda uma mensagem para objeto B;
• B usa um parâmetro da mensagem para decidir o que fazer.
capítulo 3 • 87
High cohesion (Alta coesão)
Problema:
Como manter a complexidade sob controle? As classes que fazem muitas tare-
fas não relacionadas são:
• Mais difíceis de entender;
• Mais difíceis de manter e de reusar;
• São mais vulneráveis à mudança.
Solução:
Exemplo:
3: efetuarPagamento(p:Pagamento) : void
: Pedido
capítulo 3 • 88
Suponha que isto ocorra várias vezes (outras classes), no decorrer do processo.
Pode ocorrer que Cobrança acumule métodos não relacionados a ele, provocando
uma baixa coesão da classe.
É mais coerente que o pagamento seja parte do Pedido, e não da Cobrança,
como aparecia na solução anterior; logo, Cobrança delega a responsabilidade a
Venda, aumentando a coesão de Cobrança:
1: efetuarPagamento() 2: efetuarPagamento()
<<actor>>
Cobrança : Pedido
: Cliente
2.1: criar()
p : Pagamento
Considerações
Em um bom projeto OO, cada classe deve ser construída fazer unicamente o
trabalho a que ela se propõe. Nem mais, nem menos.
A baixa coesão da classe é identificada em algumas situações, tais como:
• Quando alguns atributos começam a depender de outros.
• Quando há subgrupos de atributos correlacionados na classe.
Controller (Controlador)
Problema:
capítulo 3 • 89
Solução:
Deve ser identificada a classe que deve ser responsável por receber os eventos do
sistema e, responder a tais requisições, como num processo de troca de mensagens.
Normalmente, quando bem projetado, o controlador não realiza o trabalho,
mas delega para outras subpartes do sistema.
Exemplo:
Façade
Classes do subsistema
Figura 3.8 – Estrutura das classes do padrão Façade (GAMMA et al, 1995).
Considerações
capítulo 3 • 90
Mas, para um uso eficiente desse recurso, é necessário balancear a quantidade
de controladores. Um dos problemas mais comuns na sua implementação é o de
construir poucos controladores,provocando uma possível sobrecarga nessas classes.
Padrões avançados
Polymorphism (Polimorfismo)
Problema:
Solução:
Exemplo:
<<interface>>
IcalculadoraTaxaAdapter
+ getTaxas() : List<Taxa>
capítulo 3 • 91
Pure fabrication (Invenção pura)
Problema:
Que objeto deve ter a responsabilidade quando você não quer violar "Alta
Coesão" e "Baixo Acoplamento", mas as soluções oferecidas pelo "Especialista"
não são apropriadas?
Solução:
Exemplo:
Construir uma classe que será responsável por salvar um Pedido no banco
de dados
Apesar da classe Pedido ser a candidata lógica para ser a Expert para salvar a
si mesma em um banco de dados, isto levaria o projeto a ter baixo acoplamento,
alta coesão e baixo reuso.
Uma solução seria criar uma classe responsável somente por isto.
PedidoDB ClienteBD
Indirection (Indireção)
Problema:
capítulo 3 • 92
Solução:
Exemplo:
Cartão
Cheque
Considerações
Problema:
capítulo 3 • 93
Solução:
Exemplo:
Real
Euro
REFERÊNCIAS BIBLIOGRÁFICAS
GAMMA, ERICH et al. Design Patterns: Elements of Reusable Object-Oriented Software.
Addison-Wesley Professional. 1ª Edição. Estados Unidos da América: Addison-Wesley, 1995.
LARMAN, CRAIG. Utilizando UML e Padrões. 3ª Edição. Estados Unidos da América: Bookman,
2007.
FREEMAN,ELISABETH; FREEMAN,ERIC.Use a Cabeça! Padrões de Projetos (design Patterns).
2ª Edição. Estados Unidos da América: Alta Books, 2009.
capítulo 3 • 94
4
Arquitetura em
camadas
Arquitetura em camadas
A arquitetura de software consiste na organização dos seus componentes e suas
relações internas, assim como as relações externas, através das suas interfaces. Ela
pode ser influenciada por diversos aspectos do projeto, tais como: linguagens de
programação, sistemas operacionais e equipamentos. Por esse motivo, na medida
em que a evolução da engenharia de software acontece o tipo de arquitetura varia.
Há diversos modelos arquiteturais que podem servir de referência para os projetos
de software. Nesse capitulo, serão apresentados alguns desses modelos, suas devidas
estruturas e as vantagens e desvantagens na utilização de cada uma delas.
OBJETIVOS
• O conceito de arquitetura de software;
• A influência da arquitetura nos projetos de software;
• Os tipos mais utilizados de arquitetura de software.
Conceito
capítulo 4 • 96
relacionamento desses artefatos, de acordo com determinada visão do projeto,
como por exemplo:
• Visão de Requisitos;
• Visão do Usuário;
• Visão de Implantação;
• etc.
IMPLEMENTO01
PROJ01
IMPLEMENTO02
ESPECIF02 PROJ02
ESPECIF03
xx
xx
xx
servidor
web
capítulo 4 • 97
O Design propõe uma estrutura que prevê os componentes necessários para a
implementação do software. A medida que o projeto avança, tanto a quantidade,
quanto a disposição desses componentes pode mudar de maneira significativa.
Na Arquitetura do Software, além de haver a preocupação com a disposição
desses componentes, deve ser analisado o comportamento da aplicação quando
esses elementos interagem entre si. Aspectos como performance e integridade
dos dados são indicadores que podem ser conquistados, quando aplicada uma
arquitetura madura e já testada, mas sem o acompanhamento adequado através
de atividades de SQA (Software Quality Assurance), a qualidade do projeto não
é conquistada sem a intervenção do Arquiteto de Software, papel esse que será
abordado no tópico a seguir.
Arquitetura
1
xx
xx
xx
Mudanças em xx
1 afetam 2
2
Arquiteto de software
capítulo 4 • 98
ele ajudou a implantar no projeto. Mesmo com um histórico de implementações
bem-sucedidas, ao utilizar modelos comprovadamente eficientes, cada projeto
apresenta particularidades a medida que o software avança nas suas fases de pro-
dução, o que pode apresentar uma necessidade de mudanças no projeto.
Projetos simples
Projetos complexos
capítulo 4 • 99
• Processos bem-definidos, com um nível de maturidade a ser considerado;
• Conjunto de ferramentas complexo, tais como, ferramentas CASE, contro-
le de versão; ferramentas de integração contínua, IDEs etc.
Arquitetura monolítica
Vantagens
Desvantagens
Arquitetura multi-camadas
capítulo 4 • 100
da implementação do software, como se fossem elementos independentes, que se
comunicam mutuamente afim de manter a harmonia no processamento dos da-
dos. Em um modelo de 2 camadas, por exemplo, pode ser encontrada a seguinte
disposição dos componentes, segundo o diagrama a seguir:
Computador Servidor
<<HTTP>>
Browser WepApp
<<TCP>>
Servidor BD
<<SSGBD>>
MySQL
MVC
capítulo 4 • 101
mental
model
Controller computer
model
1
User *
Model
*
*
View
Tool
Visão (View)
Controlador (Controller)
capítulo 4 • 102
Modelo (Model)
Contém classes que se comunicam com outros sistemas para realizar tarefas
ou adquirir informações. Esta camada é implementada utilizando a tecnologia
de banco de dados, em que um SGBD executa em um ou mais nós de processa-
mento de alto desempenho. Como exemplo de implementações temos as Stored
Procedures presentes nos SGBDs (MySQL, Oracle SQL Server etc).
Vantagens
Desvantagens
Arquitetura cliente-servidor
capítulo 4 • 103
negócio das organizações. Na figura 4.7, há um desenho esquemático da interação
desses módulos:
Internet
Servidor
Clientes
Metodologia de desenvolvimento
Vantagens
capítulo 4 • 104
• Os clientes podem ser acessados de diversas plataformas. Sejam elas regidas
por dispositivos (Celular, Tablet, PC etc), ou por sistemas operacionais (Linux,
Windows etc).
Desvantagens
SOA
capítulo 4 • 105
Secure Policies
Discovery
Mechanism
pu
bli
d
sh
fin
Shield
Shield
Client interact Service
Secure
Identities Messaging Identities
Policies Policies
Trust Trust
Vantagens
capítulo 4 • 106
Desvantagens
ATIVIDADES
01. É possível desenvolver um projeto de software sem arquitetura? Justifique.
04. É recomendável utilizar arquitetura SOA para comunicar sistemas distintos, porém, que
tenham sido desenvolvidos na mesma linguagem e plataforma? Justifique.
capítulo 4 • 107
REFERÊNCIAS BIBLIOGRÁFICAS
BASS, L., P. CLEMENTS, R. KAZMAN. Software Architecture in Practice. 2ª Edição. Addison-Wesley,
2003.
BROOKS, F.P.No Silver Bullet – Essence and Accidents of Software Engineering, IEEE, 1987.
FREEMAN, ELISABETH; FREEMAN, ERIC. Use a Cabeça! Padrões de Projetos (design Patterns).
2ª Edição. Estados Unidos da América: Alta Books, 2009.
GAMMA, ERICH et al. Design Patterns: Elements of Reusable Object-Oriented Software.
Addison-Wesley Professional. 1ª Edição. Estados Unidos da América: Addison-Wesley, 1995.
LARMAN, CRAIG. Utilizando UML e Padrões. 3ª Edição. Estados Unidos da América: Prentice Hall,
2007.
PMI. A Guide to the Project Management Body of Knowledge. 5° Edição, 2013.
REENSKAUG, TRYGVE. MODELS – VIEWS – CONTROLLERS. Estados Unidos da América: Xerox
PARC technical note, 1979.
SILVEIRA, PAULO et al. Introdução à Arquitetura e Design de Software – Uma Visão Sobre a
Plataforma Java. 1ª Edição. Brasil: Elsevier, 2011.
capítulo 4 • 108
5
Aplicações práticas
dos padrões GoF
Aplicações práticas dos padrões GoF
A vida cotidiana apresenta problemas que inspiram a academia a desenvolver
soluções que facilitem a vida da sociedade de um modo geral. Essa é uma das mis-
sões dos profissionais que trabalham com tecnologia da informação.
Nesse capítulo serão apresentadas soluções práticas do uso dos padrões de
projeto abordados no livro Design Patterns (Gamma et al, 1995), e que foram
exemplificadas no capítulo 2.
São códigos fonte, comentados previamente, que fornecerão a visão arquite-
tural das implementações, quanto ao uso dos padrões de projeto do catálogo GoF.
OBJETIVOS
• Descrever problemas reais, presentes no cotidiano das organizações;
• Codificar as soluções, de acordo com o catálogo de padrões abordado.
Abstract factory
capítulo 5 • 110
GuiFactory.java
package br.estacio.abstractFactory;
abstract class GuiFactory {
public static GuiFactory obterFactory() {
if(Config.obterGuiAtual() == Config.MotifGui) {
return new MotifGuiFactory();
} else {
return new QtGuiFactory();
}
}
public abstract Botao criarBotao();
public abstract Janela criarJanela();
}
MotifGuiFactory.java
package br.estacio.abstractFactory;
class MotifGuiFactory extends GuiFactory {
public Botao criarBotao() {
return new BotaoMotif();
}
}
QtGuiFactory.java
package br.estacio.abstractFactory;
class QtGuiFactory extends GuiFactory {
public Botao criarBotao() {
return new BotaoQt();
}
}
Botao.java
package br.estacio.abstractFactory;
abstract class Botao {
public abstract void desenhar();
}
capítulo 5 • 111
BotaoMotif.java
package br.estacio.abstractFactory;
class BotaoMotif extends Botao {
publicvoid desenhar(){
System.out.println("Eu sou um botao Motif!");
}
}
BotaoQt.java
package br.estacio.abstractFactory;
class BotaoQt extends Botao {
public void desenhar(){
System.out.println("Eu sou um botao Qt!");
}
}
Janela.java
package br.estacio.abstractFactory;
abstract class Janela {
public abstract void desenhar();
}
JanelaMotif.java
package br.estacio.abstractFactory;
class JanelaMotif extends Janela {
public void desenhar(){
System.out.println("Eu sou uma janela Motif!");
}
}
JanelaQt.java
package br.estacio.abstractFactory;
class JanelaQt extends Janela {
public void desenhar(){
System.out.println("Eu sou uma janela Qt!");
}
}
capítulo 5 • 112
Cliente.java
package br.estacio.abstractFactory;
public class Cliente {
public static void main(String[] args) {
GuiFactory factory = GuiFactory.obterFactory();
Botao botao = factory.criarBotao();
botao.desenhar();
}
}
Factory method
Aplicacao.java
package br.estacio.factoryMethod;
abstract class Aplicacao {
private Documento doc;
//Abstração do Factory Method
abstract Documento criaDocumento();
void novoDocumento() {
this.doc = this.criaDocumento();
}
void abrirDocumento() {
this.doc.abrir();
}
}
MinhaAplicacao.java
package br.estacio.factoryMethod;
class MinhaAplicacao extends Aplicacao {
@Override
Documento criaDocumento() {
return new MeuDocumento();
capítulo 5 • 113
}
}
Documento.java
package br.estacio.factoryMethod;
abstract class Documento {
void abrir() {
System.out.println("Documento:Abrir documento!");
}
void fechar() {
System.out.println("Documento:Fechar documento!");
}
void salvar() {
System.out.println("Documento:Salvar documento!");
}
}
MeuDocumento.java
package br.estacio.factoryMethod;
class MeuDocumento extends Documento {
private String word = "Word";
private String excel = "Excel";
String getWord() {
return this.word;
}
String getExcel() {
return this.excel;
}
}
Cliente.java
package br.estacio.factoryMethod;
public class Cliente {
public static void main(String[] args) {
MinhaAplicacao app = new MinhaAplicacao();
capítulo 5 • 114
Documento doc = app.criaDocumento();
doc.abrir();
MeuDocumento myDoc = new MeuDocumento();
System.out.println("Documento:"+myDoc.getWord());
}
}
Builder
ConversorTexto.java
package br.estacio.builder;
abstract class ConversorTexto {
void converterCaractere(charc) {}
void converterParagrafo() {}
void converterFonte(Fonte f) {}
}
ConversorPDF.java
package br.estacio.builder;
class ConversorPDF extends ConversorTexto {
void converterCaractere(char c) {
System.out.println("Caractere PDF");
}
void converterParagrafo() {
System.out.println("Paragrafo PDF");
}
void converterFonte(Fonte f) {
System.out.println("Fonte PDF");
}
}
capítulo 5 • 115
ConversorTeX.java
package br.estacio.builder;
class ConversorTeX extends ConversorTexto {
void converterCaractere(char c) {
System.out.println("Caractere TeX");
}
void converterParagrafo() {
System.out.println("Paragrafo TeX");
}
void converterFonte(Fonte f) {
System.out.println("Fonte TeX");
}
}
ConversorASCII.java
package br.estacio.builder;
class ConversorASCII extends ConversorTexto {
void converterCaractere(char c) {
System.out.println("Caractere ASCII");
}
}
LeitorRTF.java
package br.estacio.builder;
class LeitorRTF {
private ConversorTexto conversor;
LeitorRTF(ConversorTexto c) {
this.conversor = c;
}
publicvoid lerRTF() {
List<Token>tokens = obterTokensDoTexto();
for (Token t : tokens) {
if (t.getTipo() == Token.Tipo.CARACTERE){
conversor.converterCaractere(t.getCaractere());
}
capítulo 5 • 116
if (t.getTipo() == Token.Tipo.PARAGRAFO) {
conversor.converterParagrafo();
}
if (t.getTipo() == Token.Tipo.FONTE) {
conversor.converterFonte(t.getFonte());
}
}
}
}
Cliente.java
package br.estacio.builder;
public class Cliente {
public static void main(String[] args) {
ConversorTexto conversor;
if (args[0].equals("pdf")) {
conversor = new ConversorPDF();
} else if (args[0].equals("tex")) {
conversor = new ConversorTeX();
} else {
conversor = new ConversorASCII();
}
LeitorRTF leitor = new LeitorRTF(conversor);
leitor.lerRTF();
}
}
Prototype
capítulo 5 • 117
DocumentoPrototype.java
abstract class DocumentoPrototype implements Cloneable {
protected DocumentoPrototype clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
}
return (DocumentoPrototype) clone;
}
}
ASCIIPrototype.java
package br.estacio.prototype;
class ASCIIPrototype extends DocumentoPrototype {
@Override
public String toString() {
return"Documento ASCII Criado!";
}
}
PDFPrototype.java
package br.estacio.prototype;
class ASCIIPrototype extends DocumentoPrototype {
@Override
public String toString() {
return"Documento ASCII Criado!";
}
}
capítulo 5 • 118
Cliente.jav
package br.estacio.prototype;
class Cliente {
public static void main(String[] args) {
DocumentoPrototype ascii = new ASCIIPrototype();
DocumentoPrototype pdf = new PDFPrototype();
System.out.println(ascii.clone());
System.out.println(pdf.clone());
}
}
Singleton
Singleton.java
package br.estacio.singleton;
publicclass Singleton {
private static Singleton instance = new Singleton();
int valor;
private Singleton() {
this.valor = (int) (10 * Math.random());
}
public static synchronized Singleton getInstance() {
if (instance == null)
instance = new Singleton();
returninstance;
}
}
capítulo 5 • 119
Cliente.java
package br.estacio.singleton;
public class Cliente {
public static void main(String[] args) {
Singleton singleton = null;
singleton = Singleton.getInstance();
System.out.println("Classe Singleton instanciada,
inicializada com o valor:");
System.out.println(singleton.valor);
}
}
Adapter
Software de manipulação de imagens, onde elas podem ser carregadas nos for-
matos JPG ou PNG. Caso haja a necessidade de uma imagem PNG ser convertida
para o formato JPG, ou vice-versa, o padrão Adapter sugere uma estrutura onde
essa conversão ocorra de maneira intuitiva na aplicação.
IImage.java
package br.estacio.adapter;
JpgImagem.java
package br.estacio.adapter;
public class JpgImagem {
public void carregarImagemJpg(String arquivo) {
System.out.println("Imagem " + arquivo + " carregada.");
}
capítulo 5 • 120
public void desenharImagemJpg(int largura, int altura, int posX,
int posY) {
System.out.println("Imagem JPG desenhada");
System.out.println("Largura: "+largura+" Altura: "+altura);
System.out.println("X: "+posX+" Y: "+posY);
}
}
JpgImagemAdapter.java
package br.estacio.adapter;
public class JpgImagemAdapter extends JpgImagem implements IImagem
{
@Override
public void carregarImagem(String nomeArquivo) {
carregarImagemJpg(nomeArquivo);
}
@Override
public void desenharImagem(int posX, int posY, int largura, int
altura) {
desenharImagemJpg(largura, altura, posX, posY);
}
}
PngImagem.java
package br.estacio.adapter;
public class PngImagem {
public void carregarImagemPng(String arquivo) {
System.out.println("Imagem " + arquivo + " carregada.");
}
public void desenharImagemPng(int largura, int altura, int posX,
int posY) {
System.out.println("Imagem PNG desenhada");
System.out.println("Largura: "+largura+" Altura: "+altura);
System.out.println("X: "+posX+" Y: "+posY);
}
}
capítulo 5 • 121
PngImagemAdapter.java
package br.estacio.adapter;
public class PngImagemAdapter extends PngImagem implements IImagem
{
@Override
public void carregarImagem(String nomeArquivo) {
carregarImagemPng(nomeArquivo);
}
@Override
public void desenharImagem(int posX, int posY, int largura, int
altura) {
desenharImagemPng(largura, altura, posX, posY);
}
Cliente.java
package br.estacio.adapter;
public class Cliente {
public static void main(String[] args) {
IImagem imagem = new JpgImagemAdapter();
imagem.carregarImagem("imagem.png");
imagem.desenharImagem(1, -5, 10, 10);
System.out.println("==================================");
imagem = new PngImagemAdapter();
imagem.carregarImagem("imagem.png");
imagem.desenharImagem(3, 8, 10, 100);
}
}
Bridge
capítulo 5 • 122
Janela Abstrata.java
package br.estacio.bridge;
public abstract class JanelaAbstrata {
protected JanelaImplementada janela;
public JanelaAbstrata(JanelaImplementada j) {
janela = j;
}
public void desenharJanela(String titulo) {
janela.desenharJanela(titulo);
}
public void desenharBotao(String titulo) {
janela.desenharBotao(titulo);
}
public abstract void desenhar();
}
IJanela.java
package br.estacio.bridge;
public interface IJanela {
void desenharJanela(String titulo);
void desenharBotao(String titulo);
}
JanelaWindows.java
package br.estacio.bridge;
public class JanelaWindows implements IJanela {
@Override
public void desenharJanela(String titulo) {
System.out.println(titulo + ": Janela Windows");
}
@Override
public void desenharBotao(String titulo) {
System.out.println(titulo + ": Botão Windows");
}
}
capítulo 5 • 123
JanelaLinux.java
package br.estacio.bridge;
public class JanelaLinux implements IJanela {
@Override
public void desenharJanela(String titulo) {
System.out.println(titulo + ": Janela Linux");
}
@Override
public void desenharBotao(String titulo) {
System.out.println(titulo + ": Botão Linux");
}
}
JanelaAviso.java
package br.estacio.bridge;
public class JanelaAviso extends JanelaAbstrata {
public JanelaAviso(IJanela j) {
super(j);
}
@Override
public void desenhar() {
desenharJanela("Janela de Aviso");
desenharBotao("Ok");
}
}
JanelaDialogo.java
package br.estacio.bridge;
public class JanelaDialogo extends JanelaAbstrata {
public JanelaDialogo(IJanela j) {
super(j);
}
@Override
public void desenhar() {
desenharJanela("Janela de Diálogo");
capítulo 5 • 124
desenharBotao("Botão Sim");
desenharBotao("Botão Não");
desenharBotao("Botão Cancelar");
}
}
Cliente.java
package br.estacio.bridge;
public class Cliente {
public static void main(String[] args) {
JanelaAbstrata janela = new JanelaDialogo(new
JanelaLinux());
janela.desenhar();
janela = new JanelaAviso(new JanelaLinux());
janela.desenhar();
janela = new JanelaDialogo(new JanelaWindows());
janela.desenhar();
}
}
Composite
ArquivoComponent.java
package br.estacio.composite;
public abstract class ArquivoComponent {
String nomeArquivo;
public String getNomeArquivo() {
return this.nomeArquivo;
}
capítulo 5 • 125
public void printNomeArquivo() {
System.out.println(this.nomeArquivo);
}
}
ArquivoComposite.java
package br.estacio.composite;
import java.util.ArrayList;
public class ArquivoComposite extends ArquivoComponent {
protected ArrayList<ArquivoComponent>listaArquivos;
public ArquivoComposite(String nomeArquivo) {
this.nomeArquivo = nomeArquivo;
listaArquivos = new ArrayList<ArquivoComponent>();
}
@Override
public void printNomeArquivo() {
System.out.println(this.nomeArquivo);
for (ArquivoComponent arquivoTmp : listaArquivos) {
arquivoTmp.printNomeArquivo();
}
}
public void adicionar(ArquivoComponent novoArquivo) {
this.listaArquivos.add(novoArquivo);
}
public void remover(String nomeArquivo) throws Exception {
for (ArquivoComponent arquivoTmp : listaArquivos) {
if (arquivoTmp.getNomeArquivo() == nomeArquivo){
this.listaArquivos.remove(arquivoTmp);
return;
}
}
throw new Exception("Este arquivo não existe");
}
public ArquivoComponent getArquivo(String nomeArquivo) throws
Exception {
capítulo 5 • 126
for (ArquivoComponent arquivoTmp : listaArquivos) {
if (arquivoTmp.getNomeArquivo() == nomeArquivo){
returnarquivoTmp;
}
}
throw new Exception("Este arquivo não existe");
}
}
ArquivoVideo.java
package br.estacio.composite;
public class ArquivoVideo extends ArquivoComponent {
public ArquivoVideo(String nomeArquivo) {
this.nomeArquivo = nomeArquivo;
}
}
Cliente.java
package br.estacio.composite;
public class Cliente {
public static void main(String[] args) {
ArquivoComponent video01 = new ArquivoVideo("meu video.rmvb");
ArquivoComponent video02 = new ArquivoVideo("novo video.rmvb");
ArquivoComponent pastaVideos = new Arquivo
Composite("Meus Videos/");
((ArquivoComposite) pastaVideos).adicionar(video01);
((ArquivoComposite) pastaVideos).adicionar(video02);
pastaVideos.printNomeArquivo();
}
}
Decorator
capítulo 5 • 127
Suco Tomate etc.) que irão compor o coquetel. O padrão Decorator adiciona fun-
cionalidades ao objeto em tempo de execução. Ao contrário da herança, que aplica
funcionalidades a todos os objetos dela, o padrão permite aplicar funcionalidades
apenas a um objeto específico.
Coquetel.java
package br.estacio.decorator;
public abstract class Coquetel {
String nome;
double preco;
public String getNome() {
return nome;
}
public double getPreco() {
return preco;
}
}
CoquetelDecorator.java
package br.estacio.decorator;
public abstract class CoquetelDecorator extends Coquetel{
Coquetel coquetel;
public CoquetelDecorator(Coquetel oCoquetel) {
coquetel = oCoquetel;
}
@Override
public String getNome() {
return coquetel.getNome() + " + " + nome;
}
public double getPreco() {
return coquetel.getPreco() + preco;
}
}
capítulo 5 • 128
Vodka.java
package br.estacio.decorator;
public class Vodka extends Coquetel {
public Vodka() {
nome = "Vodka";
preco = 30.0;
}
}
SucoLaranja.java
package br.estacio.decorator;
public class SucoLaranja extends CoquetelDecorator {
public SucoLaranja(Coquetel oCoquetel) {
super(oCoquetel);
nome = "Suco de Laranja";
preco = 7.5;
}
}
Cliente
package br.estacio.decorator;
public class Cliente {
public static void main(String[] args) {
Coquetel coquetel = new Vodka();
System.out.println(coquetel.getNome() + ": "+
coquetel.getPreco());
coquetel = new SucoLaranja(coquetel);
System.out.println(coquetel.getNome() + ": "+
coquetel.getPreco());
}
}
capítulo 5 • 129
Façade
Facade.java
package br.estacio.facade;
public class Facade {
protected Funcionario funcionario;
protected Cargo cargo;
protected Setor setor;
public Facade() {
setor = new Setor();
cargo = new Cargo();
funcionario = new Funcionario();
}
public void getFuncionario() {
funcionario.getFuncionario();
}
public void getCargo() {
cargo.getCargo();
}
public void getSetor() {
setor.getSetor();
}
}
Funcionario.java
package br.estacio.facade;
public class Funcionario {
private String nome;
private int matricula;
capítulo 5 • 130
public Funcionario() {
this.nome = "Luiz Leão";
this.matricula = 123456;
}
public void getFuncionario() {
System.out.println("Nome: "+nome);
System.out.println("Matricula: "+matricula);
}
}
Cargo.java
package br.estacio.facade;
public class Cargo {
private String descricao;
private Double salario;
public Cargo() {
this.descricao = "Programador";
this.salario = 2500.0;
}
public void getCargo() {
System.out.println("Cargo: "+descricao);
System.out.println("Salario: R$ "+salario);
}
}
Setor.java
package br.estacio.facade;
public class Setor {
private String descricao;
public Setor() {
this.descricao = "CPD";
}
capítulo 5 • 131
public void getSetor() {
System.out.println("Setor: "+descricao);
}
}
Cliente.java
package br.estacio.facade;
public class Cliente {
public static void main(String[] args) {
Facade oFacade = new Facade();
System.out.println("====================");
oFacade.getFuncionario();
System.out.println("====================");
oFacade.getCargo();
System.out.println("====================");
oFacade.getSetor();
}
}
Flyweight
ElementoFlyweight.java
package br.estacio.flyweight;
public abstract class ElementoFlyweight {
public abstract void desenharImagem(Ponto ponto);
}
capítulo 5 • 132
Elemento.java
package br.estacio.flyweight;
public class Elemento extends ElementoFlyweight {
protected Imagem imagem;
public Elemento(String nomeImagem) {
imagem = new Imagem(nomeImagem);
}
@Override
public void desenharImagem(Ponto ponto) {
imagem.desenharImagem();
System.out.println(" => Ponto (" + ponto.x + "," +ponto.y +
")");
}
}
FlyweightFactory.java
package br.estacio.flyweight;
import java.util.ArrayList;
public class FlyweightFactory {
protected ArrayList<ElementoFlyweight>flyweights;
public FlyweightFactory() {
flyweights = new ArrayList<ElementoFlyweight>();
flyweights.add(new Elemento("jogador.png"));
flyweights.add(new Elemento("inimigo01.png"));
flyweights.add(new Elemento("inimigo02.png"));
flyweights.add(new Elemento("inimigo03.png"));
flyweights.add(new Elemento("obstaculo01.png"));
flyweights.add(new Elemento("obstaculo02.png"));
}
public ElementoFlyweight getFlyweight(EnumElementos
componente) {
switch (componente) {
case JOGADOR: return flyweights.get(0);
case INIMIGO01: return flyweights.get(1);
case INIMIGO02: return flyweights.get(2);
case INIMIGO03: return flyweights.get(3);
capítulo 5 • 133
case OBSTACULO01: return flyweights.get(4);
default: return flyweights.get(5);
}
}
}
Imagem.java
package br.estacio.flyweight;
public class Imagem {
protected String nomeImagem;
public Imagem(String imagem) {
nomeImagem = imagem;
}
public void desenharImagem() {
System.out.print(nomeImagem + desenharPontinhos() + "
Criado");
}
public String desenharPontinhos() {
String pontos = "";
int tamanho = 22 - nomeImagem.length();
for(int i=0; i<tamanho; i++) {
pontos += ".";
}
return pontos;
}
}
Ponto.java
package br.estacio.flyweight;
public class Ponto {
public int x, y;
public Ponto(int x, int y) {
this.x = x;
this.y = y;
}
}
capítulo 5 • 134
Cliente.java
package br.estacio.flyweight;
public class Cliente {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
System.out.println("==============================");
System.out.println("Renderizando o Cenário do Jogo");
System.out.println("==============================");
factory
.getFlyweight(EnumElementos.OBSTACULO01)
.desenharImagem(new Ponto(0, 0));
factory
.getFlyweight(EnumElementos.JOGADOR)
.desenharImagem(new Ponto(10, 10));
factory
.getFlyweight(EnumElementos.INIMIGO01)
.desenharImagem(new Ponto(100, 10));
factory
.getFlyweight(EnumElementos.INIMIGO01)
.desenharImagem(new Ponto(120, 10));
factory
.getFlyweight(EnumElementos.INIMIGO01)
.desenharImagem(new Ponto(140, 10));
factory
.getFlyweight(EnumElementos.OBSTACULO02)
.desenharImagem(new Ponto(5, 33));
factory
.getFlyweight(EnumElementos.INIMIGO02)
.desenharImagem(new Ponto(60, 10));
factory
.getFlyweight(EnumElementos.INIMIGO02)
.desenharImagem(new Ponto(50, 10));
factory
.getFlyweight(EnumElementos.INIMIGO03)
.desenharImagem(new Ponto(170, 10));
}
}
capítulo 5 • 135
Proxy
Banco.java
package br.estacio.proxy;
public class Banco {
private int totalClientes;
private double saldoClientes;
public Banco() {
totalClientes = (int) (Math.random() * 100);
saldoClientes = (double) (Math.random() * 100000);
}
public String getTotalClientes() {
return new String("Total de clientes: " + totalClientes);
}
public String getSaldoClientes() {
return new String("Saldo Total dos Clientes: R$ " +
saldoClientes);
}
}
BancoProxy.java
package br.estacio.proxy;
public class BancoProxy extends Banco {
protected String usuario, senha;
public BancoProxy(String usuario, String senha) {
this.usuario = usuario;
this.senha = senha;
}
capítulo 5 • 136
@Override
public String getTotalClientes() {
if (checarPermissao()) {
return super.getTotalClientes();
}
return null;
}
@Override
public String getSaldoClientes() {
if (checarPermissao()) {
return super.getSaldoClientes();
}
return null;
}
private boolean checarPermissao() {
return (usuario == "gerente"&&senha == "gerente") ? true :
false;
}
}
Cliente.java
package br.estacio.proxy;
public class Cliente {
public static void main(String[] args) {
System.out.println("Acesso do Hacker");
Banco banco = new BancoProxy("Hacker", "1234");
System.out.println(banco.getTotalClientes());
System.out.println(banco.getSaldoClientes());
System.out.println("================================");
System.out.println("Acesso do Gerente");
banco = new BancoProxy("gerente", "gerente");
System.out.println(banco.getTotalClientes());
System.out.println(banco.getSaldoClientes());
}
}
capítulo 5 • 137
Chain of responsibility
Pagamento Chain.java
package br.estacio.chain;
public abstract class PagamentoChain {
protected PagamentoChain proximo;
protected EnumPagamentos idBanco;
public PagamentoChain(EnumPagamentos banco) {
proximo = null;
idBanco = banco;
}
public void setProximo(PagamentoChain forma) {
if (proximo == null) {
proximo = forma;
} else {
proximo.setProximo(forma);
}
}
public void efetuarPagamento(EnumPagamentos banco) throws
Exception {
if (verificarPagamento(banco)) {
efetuarPagamento();
} else {
if (proximo == null) {
capítulo 5 • 138
throw new Exception(banco + ": .......Forma de Pagamento
Não Cadastrada");
}
proximo.efetuarPagamento(banco);
}
}
private boolean verificarPagamento(EnumPagamentos banco) {
if (idBanco == banco) {
return true;
}
return false;
}
protected abstract void efetuarPagamento();
}
EnumPagamentos.java
package br.estacio.chain;
public enum EnumPagamentos {
CARTAOA, CARTAOB, BOLETO, CARTAOC
}
Boleto.java
package br.estacio.chain;
public class Boleto extends PagamentoChain {
public Boleto() {
super(EnumPagamentos.BOLETO);
}
@Override
protected void efetuarPagamento() {
System.out.println("Pagamento efetuado: Boleto");
}
}
capítulo 5 • 139
CartaoA.java
package br.estacio.chain;
public class CartaoA extends PagamentoChain {
public CartaoA() {
super(EnumPagamentos.CARTAOA);
}
@Override
protected void efetuarPagamento() {
System.out.println("Pagamento efetuado: Cartão A");
}
}
CartaoB.java
package br.estacio.chain;
public class CartaoB extends PagamentoChain {
public CartaoB() {
super(EnumPagamentos.CARTAOB);
}
@Override
protected void efetuarPagamento() {
System.out.println("Pagamento efetuado: Cartão B");
}
}
Cliente.java
package br.estacio.chain;
public class Cliente {
public static void main(String[] args) {
PagamentoChain bancos = new CartaoA();
bancos.setProximo(new CartaoB());
bancos.setProximo(new Boleto());
try {
bancos.efetuarPagamento(EnumPagamentos.BOLETO);
bancos.efetuarPagameto(EnumPagamentos.CARTAOA);
bancos.efetuarPagameto(EnumPagamentos.CARTAOB);
capítulo 5 • 140
bancos.efetuarPagameto(EnumPagamentos.CARTAOC);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
Command
Uma loja que vende produtos e oferece várias formas de pagamento. Ao exe-
cutar uma compra, o sistema registra o seu valor e, de acordo com a forma de
pagamento selecionada, por exemplo, cartão de crédito, emite o valor total da
compra para o cartão de crédito do cliente, exibindo a quantidade de parcelas.
Outras formas de pagamento, como boleto bancário, teriam outras informações
relacionadas a compra, e assim por diante. Para este caso, vamos supor as seguintes
classes para simplificar o exemplo: Loja e Compra.
O padrão Command utiliza apenas da herança para agrupar classes e obrigar
que todas tenham uma mesma interface em comum. Inicialmente o padrão pode
ser confundido com o padrão Template Method, pois ambos utilizam a herança
para unificar a interface de várias classes.
A diferença reside no fato do padrão Command não utilizar o conceito de
um algoritmo que será executado. Já no padrão Template Method, as subclasses
concretas definem apenas algumas operações, sem alterar o esqueleto de execução.
O Command não oferece uma maneira de execução de suas subclasses, apenas
garante que todas executem determinada requisição.
PagamentoCommand.java
package br.estacio.command;
public interface PagamentoCommand {
void processarCompra(Compra compra);
}
Compra.java
package br.estacio.command;
public class Compra {
private static int CONT;
capítulo 5 • 141
protected int numNotaFiscal;
protected String nomeLoja;
protected double valorTotal;
public Compra(String nomeLoja) {
this.nomeLoja = nomeLoja;
numNotaFiscal = ++CONT;
}
public void setValor(double valor) {
this.valorTotal = valor;
}
public String getInfoNota() {
StringBuffer linha = new StringBuffer();
linha.append("| Nota fiscal nº: " + numNotaFiscal+"\n");
linha.append("| Loja: "+ nomeLoja+"\n");
linha.append("| Valor: " + valorTotal+"\n");
return linha.toString();
}
}
Loja.java
package br.estacio.command;
public class Loja {
protected String nome;
public Loja(String nome) {
this.nome = nome;
}
public void executarCompra(double valor, PagamentoCommand
formaPagamento) {
Compra compra = new Compra(nome);
compra.setValor(valor);
formaPagamento.processarCompra(compra);
}
}
capítulo 5 • 142
PagamentoBoleto.java
package br.estacio.command;
public class PagamentoBoleto implements PagamentoCommand {
@Override
public void processarCompra(Compra compra) {
System.out.println(compra.getInfoNota() + "| Forma de
Pagamento: ........ Boleto");
}
}
PagamentoCartãoCredito.java
package br.estacio.command;
public class PagamentoCartaoCredito implements PagamentoCommand {
int qtdParcelas;
PagamentoCartaoCredito(int qtdParcelas) {
this.qtdParcelas = qtdParcelas;
}
@Override
public void processarCompra(Compra compra) {
System.out.println(compra.getInfoNota() + "| Forma de
Pagamento: ........ Cartao de Credito");
System.out.println("| Quantidade de Parcelas: ....
"+qtdParcelas);
}
}
PagamentoCartãoDebito.java
package br.estacio.command;
public class PagamentoCartaoDebito implements PagamentoCommand {
@Override
public void processarCompra(Compra compra) {
System.out.println(compra.getInfoNota() + "| Forma de
Pagamento: ........ Cartao de Debito");
}
}
capítulo 5 • 143
Cliente.java
package br.estacio.command;
public class Cliente {
public static void main(String[] args) {
Loja baratao = new Loja("Baratão");
baratao.executarCompra(999.00, new PagamentoCartao
Credito(2));
System.out.println("==============================");
baratao.executarCompra(49.00, new PagamentoBoleto());
System.out.println("==============================");
baratao.executarCompra(99.00, new PagamentoCartao
Debito());
System.out.println("==============================");
Loja joaoEletro = new Loja("João Eletro");
joaoEletro.executarCompra(19.00, new PagamentoCartao
Credito(3));
}
}
Interpreter
NumRomanoInterpreter.java
package br.estacio.interpreter;
public abstract class NumRomanoInterpreter {
public void interpretar(Contexto contexto) {
capítulo 5 • 144
if (contexto.getInput().length() == 0) {
return;
}
// 4 e 9 tem duascasas
if (contexto.getInput().startsWith(nove())) {
addValorOutput(contexto, 9);
useDuasCasasInput(contexto);
} else if(contexto.getInput().startsWith(quatro())) {
addValorOutput(contexto, 4);
useDuasCasasInput(contexto);
} else if (contexto.getInput().startsWith(cinco())) {
addValorOutput(contexto, 5);
useUmaCasaInput(contexto);
}
// valoresquese repetem: III, CCC, MMM
while (contexto.getInput().startsWith(um())) {
addValorOutput(contexto, 1);
useUmaCasaInput(contexto);
}
}
private void useUmaCasaInput(Contexto contexto) {
contexto.setInput(contexto.getInput().substring(1));
}
private void useDuasCasasInput(Contexto contexto) {
contexto.setInput(contexto.getInput().substring(2));
}
private void addValorOutput(Contexto contexto, int numero){
contexto.setOutput(contexto.getOutput() + (numero *
multiplicador()));
}
public abstract String um();
public abstract String quatro();
public abstract String cinco();
public abstract String nove();
public abstract int multiplicador();
}
capítulo 5 • 145
Contexto.java
package br.estacio.interpreter;
public class Contexto {
protected String input;
protected int output;
public Contexto(String input) {
this.input = input;
}
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
public int getOutput() {
return output;
}
public void setOutput(int output) {
this.output = output;
}
}
UnidadeRomano.java
package br.estacio.interpreter;
public class UnidadeRomano extends NumRomanoInterpreter {
@Override
public String um() {
return"I";
}
@Override
public String quatro() {
return"IV";
}
@Override
public String cinco() {
return"V";
}
capítulo 5 • 146
@Override
public String nove() {
return"IX";
}
@Override
public int multiplicador() {
return 1;
}
}
DezenaRomano.java
package br.estacio.interpreter;
public class DezenaRomano extends NumRomanoInterpreter {
@Override
public String um() {
return "X";
}
@Override
public String quatro() {
return "XL";
}
@Override
public String cinco() {
return "L";
}
@Override
public String nove() {
return "XC";
}
@Override
public int multiplicador() {
return 10;
}
}
capítulo 5 • 147
CentenaRomano.java
package br.estacio.interpreter;
public class CentenaRomano extends NumRomanoInterpreter {
@Override
public String um() {
return "C";
}
@Override
public String quatro() {
return "CD";
}
@Override
public String cinco() {
return "D";
}
@Override
public String nove() {
return "CM";
}
@Override
public int multiplicador() {
return 100;
}
}
MilharRomano.java
package br.estacio.interpreter;
public class MilharRomano extends NumRomanoInterpreter {
@Override
public String um() {
return "M";
}
@Override
public String quatro() {
return " ";
}
capítulo 5 • 148
@Override
public String cinco() {
return " ";
}
@Override
public String nove() {
return " ";
}
@Override
public int multiplicador() {
return 1000;
}
}
Cliente.java
package br.estacio.interpreter;
import java.util.ArrayList;
public class Cliente {
public static void main(String[] args) {
ArrayList<NumRomanoInterpreter>aInterpreter = new Array
List<NumRomanoInterpreter>();
aInterpreter.add(new MilharRomano());
aInterpreter.add(new CentenaRomano());
aInterpreter.add(new DezenaRomano());
aInterpreter.add(new UnidadeRomano());
String valorRomano = "MMMDLVIII";
Contexto contexto = new Contexto(valorRomano);
for (NumRomanoInterpreter numRomanoInterpreter : aInterpreter)
{
numRomanoInterpreter.interpretar(contexto);
}
System.out.println(valorRomano + " = " + Integer.
toString(contexto.getOutput()));
}
}
capítulo 5 • 149
Iterator
IteradorCanais.java
package br.estacio.iterator;
import java.util.ArrayList;
public class IteradorCanais {
ArrayList<Canal>lista;
int contador;
protected IteradorCanais(ArrayList<Canal>lista) {
this.lista = lista;
contador = 0;
}
public void first() {
contador = 0;
}
public void proximoCanal() {
contador++;
}
public void voltarCanal() {
34stacio34 --;
}
public 34stacio isDone() {
return 34stacio34 == lista.size();
}
private Canal currentItem() {
if (isDone()) {
contador = lista.size() – 1;
} else if (contador< 0) {
contador = 0;
}
capítulo 5 • 150
return lista.get(34stacio34);
}
public String getNomeCanal() {
return currentItem().nome;
}
public int getNumeroCanal() {
return currentItem().numero;
}
}
CanaisAgregado.java
package br.estacio.iterator;
import java.util.ArrayList;
CanaisNoticia.java
package br.estacio.iterator;
public class CanaisNoticia extends CanaisAgregado {
public CanaisNoticia() {
canais.add(new Canal("Blogo News", 11));
canais.add(new Canal("Bland Noticias", 3));
canais.add(new Canal("Gazeta Belenense", 21));
capítulo 5 • 151
canais.add(new Canal("Valarejo Alerta", 41));
}
}
Canal.java
package br.estacio.iterator;
public class Canal {
String nome;
int numero;
public Canal(String nome, int numero) {
this.nome = nome;
this.numero = numero;
}
}
Cliente.java
package br.estacio.iterator;
public class Cliente {
public static void main(String[] args) {
CanaisNoticia canais = new CanaisNoticia();
System.out.println("==========================");
System.out.println("Iterando com for:”);
System.out.println("==========================");
for (IteradorCanais it = canais.criarIterator(); !it.
isDone(); it.
proximoCanal()) {
System.out.println(it.getNumeroCanal() + "–" + it.get
NomeCanal());
}
System.out.println("==========================");
System.out.println("Iterando manualmente: ");
System.out.println("==========================");
IteradorCanais it = canais.criarIterator();
System.out.println(it.getNumeroCanal() + "–" + it.get
NomeCanal());
capítulo 5 • 152
it.proximoCanal();
System.out.println(it.getNumeroCanal() + "–" + it.get
NomeCanal());
it.proximoCanal();
System.out.println(it.getNumeroCanal() + "–" + it.get
NomeCanal());
it.proximoCanal();
System.out.println(it.getNumeroCanal() + "–" + it.get
NomeCanal());
System.out.println("\nIterando além dos limites:");
it.proximoCanal();
System.out.println(it.getNumeroCanal() + "–" + it.get
NomeCanal());
it.first();
it.voltarCanal();
System.out.println(it.getNumeroCanal() + "–" + it.get
NomeCanal());
}
}
Mediator
Mediator.java
package br.estacio.mediator;
public interface Mediator {
void enviar(String mensagem, Colleague colleague);
}
capítulo 5 • 153
MensagemMediator.java
package br.estacio.mediator;
import java.util.ArrayList;
public class MensagemMediator implements Mediator {
protected ArrayList<Colleague>contatos;
public MensagemMediator() {
contatos = new ArrayList<Colleague>();
}
public void adicionarColleague(Colleague colleague) {
contatos.add(colleague);
}
@Override
public void enviar(String mensagem, Colleague colleague) {
for (Colleague contato : contatos) {
if (contato != colleague) {
definirProtocolo(contato);
contato.receberMensagem(mensagem);
}
}
}
private void definirProtocolo(Colleague contato) {
if (contato instanceof IOSColleague) {
System.out.println("Dispositivo:..... iOS");
} else if (contato instanceof AndroidColleague) {
System.out.println("Dispositivo:..... Android");
} else if (contato instanceof WindowsPhoneColleague) {
System.out.println("Dispositivo:..... Windows Phone");
}
}
}
Colleague.java
package br.estacio.mediator;
public abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator m) {
capítulo 5 • 154
mediator = m;
}
public void enviarMensagem(String mensagem) {
mediator.enviar(mensagem, this);
}
publicabstractvoid receberMensagem(String mensagem);
}
AndroidColleague.java
package br.estacio.mediator;
public class AndroidColleague extends Colleague {
public AndroidColleague(Mediator m) {
super(m);
}
@Override
public void receberMensagem(String mensagem) {
System.out.println("Android recebeu: " + mensagem);
}
}
IOSColleague.java
package br.estacio.mediator;
public class IOSColleague extends Colleague {
public IOSColleague(Mediator m) {
super(m);
}
@Override
public void receberMensagem(String mensagem) {
System.out.println("iOs recebeu: " + mensagem);
}
}
WindowsPhoneColleague.java
package br.estacio.mediator;
public class WindowsPhoneColleague extends Colleague {
public WindowsPhoneColleague(Mediator m) {
capítulo 5 • 155
super(m);
}
@Override
public void receberMensagem(String mensagem) {
System.out.println("Windows Phone recebeu: " + mensagem);
}
}
Cliente.java
package br.estacio.mediator;
public class Cliente {
public static void main(String[] args) {
MensagemMediator mediador = new MensagemMediator();
AndroidColleague android = new AndroidColleague(mediador);
IOSColleague ios = new IOSColleague(mediador);
WindowsPhoneColleague 39stacio = new Windows
PhoneColleague(mediador);
mediador.addColleague(android);
mediador.addColleague(ios);
mediador.addColleague(symbian);
symbian.enviarMensagem("Oi, eu sou um Symbian!");
System.out.println("================================");
android.enviarMensagem("Oi Windows Phone! Eu sou um Android!");
System.out.println("================================");
ios.enviarMensagem("Olá todos, sou um iOs!");
}
}
Memento
capítulo 5 • 156
salvar todas as informações necessárias em Memento e, quando necessário, recu-
perá-las. Ele transfere a responsabilidade de fornecer maneiras de acessar o estado
para o objeto Memento, deixando o Originator (nesse exemplo, a classe Texto)
livre desta responsabilidade.
TextoMemento.java
package br.estacio.memento;
public class TextoMemento {
protected String estadoTexto;
public TextoMemento(String texto) {
estadoTexto = texto;
}
public String getTextoSalvo() {
returnestadoTexto;
}
}
TextoCareTaker.java
package br.estacio.memento;
import java.util.ArrayList;
public class TextoCareTaker {
protected ArrayList<TextoMemento>estados;
public TextoCareTaker() {
estados = new ArrayList<TextoMemento>();
}
public void addMemento(TextoMemento memento) {
estados.add(memento);
}
public TextoMemento getUltimoEstadoSalvo() {
if (estados.size() <= 0) {
returnnew TextoMemento("");
}
TextoMemento estadoSalvo = estados.get(estados.size() – 1);
estados.remove(estados.size() – 1);
return estadoSalvo;
}
}
capítulo 5 • 157
Texto.java
package br.estacio.memento;
public class Texto {
protected String texto;
TextoCareTaker caretaker;
public Texto() {
caretaker = new TextoCareTaker();
texto = new String();
}
public void addTexto(String novoTexto) {
caretaker.addMemento(new TextoMemento(texto));
texto += novoTexto+"\n";
}
public void undoTexto() {
texto = caretaker.getUltimoEstadoSalvo().getTextoSalvo();
}
public void showTexto() {
System.out.println(texto);
}
}
Cliente.java
package br.estacio.memento;
public class Cliente {
public static void main(String[] args) {
Texto texto = new Texto();
texto.addTexto("Texto da linha 1");
texto.addTexto("Texto da linha 2");
texto.addTexto("Texto da linha 1");
texto.showTexto();
texto.undoTexto();
texto.showTexto();
texto.undoTexto();
texto.showTexto();
texto.undoTexto();
texto.showTexto();
capítulo 5 • 158
texto.undoTexto();
texto.showTexto();
}
}
Observer
DadosObserver.java
package br.estacio.observer;
public abstract class DadosObserver {
protected DadosSubject dados;
public DadosObserver(DadosSubject dados) {
this.dados = dados;
}
public abstract void update();
}
Dados.java
package br.estacio.observer;
public class Dados {
int valorA, valorB, valorC;
public Dados(int a, int b, int c) {
valorA = a;
valorB = b;
valorC = c;
}
}
capítulo 5 • 159
DadosSubject.java
package br.estacio.observer;
import java.util.ArrayList;
public class DadosSubject {
protected ArrayList<DadosObserver>observers;
protected Dados dados;
public DadosSubject() {
observers = new ArrayList<DadosObserver>();
}
public void attach(DadosObserver observer) {
observers.add(observer);
}
public void detach(intindice) {
observers.remove(indice);
}
public void setState(Dados dados) {
this.dados = dados;
notifyObservers();
}
private void notifyObservers() {
for (DadosObserver observer : observers) {
observer.update();
}
}
public Dados getState() {
return dados;
}
}
Barra Observer.java
package br.estacio.observer;
public class BarraObserver extends DadosObserver {
public BarraObserver(DadosSubject dados) {
super(dados);
}
capítulo 5 • 160
@Override
public void update() {
String barraA = "", barraB = "", barraC = "";
for (inti = 0; i<dados.getState().valorA; i++)
barraA += '=';
for (inti = 0; i<dados.getState().valorB; i++)
barraB += '=';
for (inti = 0; i<dados.getState().valorC; i++)
barraC += '=';
System.out.println("Barras:");
System.out.println("Valor A: " + barraA);
System.out.println("Valor B: " + barraB);
System.out.println("Valor A: " + barraC);
}
}
PercentualObserver.java
package br.estacio.observer;
import java.text.DecimalFormat;
public class PercentualObserver extends DadosObserver {
public PercentualObserver(DadosSubject dados) {
super(dados);
}
@Override
public void update() {
int totalValores = dados.getState().valorA + dados.getState().
valorB + dados.getState().valorC;
DecimalFormat format = new DecimalFormat("#.##");
String porcentagemA = format.format((double) dados.getState().
valorA / totalValores);
String porcentagemB = format.format((double) dados.getState().
valorB / totalValores);
String porcentagemC = format.format((double) dados.getState().
valorC / totalValores);
System.out.println("Porcentagem:");
System.out.println("Valor A: " + porcentagemA + "%");
capítulo 5 • 161
System.out.println("Valor B: " + porcentagemB + "%");
System.out.println("Valor C: " + porcentagemC + "%");
}
}
TabelaObserver.java
package br.estacio.observer;
public class TabelaObserver extends DadosObserver {
public TabelaObserver(DadosSubject dados) {
super(dados);
}
@Override
public void update() {
System.out.println("Tabela:");
System.out.println("Valor A: "+ dados.getState().valorA);
System.out.println("Valor B: "+ dados.getState().valorB);
System.out.println("Valor C: "+ dados.getState().valorC);
}
}
Cliente.java
package br.estacio.observer;
public class Cliente {
public static void main(String[] args) {
DadosSubject dados = new DadosSubject();
dados.attach(new TabelaObserver(dados));
dados.attach(new BarraObserver(dados));
dados.attach(new PercentualObserver(dados));
dados.setState(new Dados(7, 3, 1));
dados.setState(new Dados(2, 3, 1));
}
}
capítulo 5 • 162
State
MarioState.java
package br.estacio.state;
public interface MarioState {
MarioState pegarCogumelo();
MarioState pegarFlor();
MarioState pegarPena();
MarioState sofrerDano();
}
Mario.java
package br.estacio.state;
public class Mario {
protected MarioState estado;
public Mario() {
estado = new MarioPequeno();
}
public void pegarCogumelo() {
estado = estado.pegarCogumelo();
}
public void pegarFlor() {
estado = estado.pegarFlor();
}
public void pegarPena() {
estado = estado.pegarPena();
}
capítulo 5 • 163
public void levarDano() {
estado = estado.sofrerDano();
}
}
Mario Pequeno.java
package br.estacio.state;
public class MarioPequeno implements MarioState {
@Override
public MarioState pegarCogumelo() {
System.out.println("Mario grande");
return new MarioGrande();
}
@Override
public MarioState pegarFlor() {
System.out.println("Mario grande com fogo");
return new MarioFogo();
}
@Override
public MarioState pegarPena() {
System.out.println("Mario grande com capa");
return new MarioCapa();
}
@Override
public MarioState sofrerDano() {
System.out.println("Mario morto");
return new MarioMorto();
}
}
MarioGrande.java
package br.estacio.state;
public class MarioGrande implements MarioState {
@Override
public MarioState pegarCogumelo() {
capítulo 5 • 164
System.out.println("Mario ganhou 1000 pontos");
return this;
}
@Override
public MarioState pegarFlor() {
System.out.println("Mario com fogo");
return new MarioFogo();
}
@Override
public MarioState pegarPena() {
System.out.println("Mario com capa");
return new MarioCapa();
}
@Override
public MarioState sofrerDano() {
System.out.println("Mario pequeno");
return new MarioPequeno();
}
}
MarioFogo.java
package br.estacio.state;
public class MarioFogo implements MarioState {
@Override
public MarioState pegarCogumelo() {
System.out.println("Mario ganhou 1000 pontos");
return this;
}
@Override
public MarioState pegarFlor() {
System.out.println("Mario ganhou 1000 pontos");
return this;
}
capítulo 5 • 165
@Override
public MarioState pegarPena() {
System.out.println("Mario com capa");
return new MarioCapa();
}
@Override
public MarioState sofrerDano() {
System.out.println("Mario grande");
return new MarioGrande();
}
}
MarioPena.java
package br.estacio.state;
public class MarioGrande implements MarioState {
@Override
public MarioState pegarCogumelo() {
System.out.println("Mario ganhou 1000 pontos");
return this;
}
@Override
public MarioState pegarFlor() {
System.out.println("Mario com fogo");
return new MarioFogo();
}
@Override
public MarioState pegarPena() {
System.out.println("Mario com capa");
return new MarioCapa();
}
@Override
public MarioState sofrerDano() {
System.out.println("Mario pequeno");
return new MarioPequeno();
}
}
capítulo 5 • 166
MarioMorto.java
package br.estacio.state;
public class MarioMorto implements MarioState {
@Override
public MarioState pegarCogumelo() {
return null;
}
@Override
public MarioState pegarFlor() {
return null;
}
@Override
public MarioState pegarPena() {
return null;
}
@Override
public MarioState sofrerDano() {
return null;
}
}
Cliente.java
package br.estacio.state;
public class Cliente {
public static void main(String[] args) {
Mario mario = new Mario();
mario.pegarCogumelo();
mario.pegarPena();
mario.levarDano();
mario.pegarFlor();
mario.pegarFlor();
mario.levarDano();
mario.levarDano();
mario.pegarPena();
mario.levarDano();
mario.levarDano();
capítulo 5 • 167
mario.levarDano();
}
}
Strategy
StrategyCalculoImposto.java
package br.estacio.strategy;
interface StrategyCalculoImposto {
double calcularSalarioImposto(Funcionario oFuncionario);
}
CalculoImposto10_15.java
package br.estacio.strategy;
public class CalculoImposto10_15 implements StrategyCalculoImposto
{
@Override
public double calcularSalarioImposto(Funcionario oFuncionario)
{
if (oFuncionario.getSalarioBase() > 2000) {
return oFuncionario.getSalarioBase() * 0.85;
}
return oFuncionario.getSalarioBase() * 0.9;
}
}
capítulo 5 • 168
CalculoImposto15_20.java
package br.estacio.strategy;
public class CalculoImposto15_20 implements StrategyCalculoImposto
{
@Override
public double calcularSalarioImposto(Funcionario oFuncionario)
{
if (oFuncionario.getSalarioBase() > 3500) {
return oFuncionario.getSalarioBase() * 0.8;
}
return oFuncionario.getSalarioBase() * 0.85;
}
}
Funcionario.java
package br.estacio.strategy;
public class Funcionario {
public static final int DESENVOLVEDOR = 1;
public static final int GERENTE = 2;
public static final int DBA = 3;
protected double salarioBase;
protected int cargo;
protected String descricaoCargo;
protected StrategyCalculoImposto strategyCalculo;
public Funcionario(int cargo, double salarioBase) {
this.salarioBase = salarioBase;
switch (cargo) {
case DESENVOLVEDOR:
strategyCalculo = new CalculoImposto10_15();
descricaoCargo = "DESENVOLVEDOR";
break;
case DBA:
strategyCalculo = new CalculoImposto10_15();
descricaoCargo = "DBA";
break;
capítulo 5 • 169
case GERENTE:
strategyCalculo = new CalculoImposto15_20();
descricaoCargo = "GERENTE";
break;
default:
throw new RuntimeException("Cargo não encontrado");
}
}
public double calcularSalarioImposto() {
return strategyCalculo.calcularSalarioImposto(this);
}
public double getSalarioBase() {
return salarioBase;
}
public String getDescricaoCargo() {
return descricaoCargo;
}
}
Cliente.java
package br.estacio.strategy;
public class Cliente {
public static void main(String[] args) {
try{
Funcionario oFuncionario1 = new Funcionario(Funcionario.DESENVOL
VEDOR, 2100);
System.out.println("Cargo: " + oFuncionario1.getDescricaoCargo());
System.out.println("Salario Bruto: " + oFuncionario1.
getSalarioBase());
System.out.println("Salario Liquido: " + oFuncionario1.calcularSalario
Imposto());
System.out.println("=====================================");
capítulo 5 • 170
Funcionario oFuncionario2 = new Funcionario(Funcionario.DBA, 1700);
System.out.println("Cargo: " + oFuncionario2.getDescricaoCargo());
System.out.println("Salario Bruto: " +
oFuncionario2.getSalarioBase());
System.out.println("Salario Liquido: " + oFuncionario2.calcularSalario
Imposto());
S y s t e m . o u t . p r i n t l n ( " = = = = = = = = = = = = = = = = = = = = = =
====================");
Funcionario oFuncionario3 = new Funcionario(Funcionario.GERENTE,
10000);
System.out.println("Cargo: " + oFuncionario3.getDescricaoCargo());
System.out.println("Salario Bruto: " +
oFuncionario3.getSalarioBase());
System.out.println("Salario Liquido: " + oFuncionario3.calcularSalario
Imposto());
System.out.println("==================================");
} catch(RuntimeException e) {
System.out.println("Erro: "+e.getMessage());
}
}
}
Template Method
capítulo 5 • 171
OrdenarTemplate.java
package br.estacio.templateMethod;
import java.util.ArrayList;
public abstract class OrdenarTemplate {
public abstract boolean isPrimeiro(Musica musica1,
Musica musica2);
protected ArrayList<Musica>
ordenarMusica(ArrayList<Musica>lista) {
ArrayList<Musica>aListaMusica = new ArrayList<Musica>();
for (Musica musicaMP3 : lista) {
aListaMusica.add(musicaMP3);
}
for (inti = 0; i<aListaMusica.size(); i++) {
for (intj = i; j<aListaMusica.size(); j++) {
if (!isPrimeiro(aListaMusica.get(i), aListaMusica.
get(j))) {
Musica temp = aListaMusica.get(j);
aListaMusica.set(j, aListaMusica.get(i));
aListaMusica.set(i, temp);
}
}
}
returna ListaMusica;
}
}
EnumModoReproducao.java
package br.estacio.templateMethod;
public enum EnumModoReproducao {
NOME, AUTOR, ANO, ESTRELA
}
capítulo 5 • 172
OrdenarAno.java
package br.estacio.templateMethod;
public class OrdenarAno extends OrdenarTemplate {
@Override
public boolean isPrimeiro(Musica musica1, Musica musica2) {
if (musica1.ano.compareToIgnoreCase(musica2.ano) <= 0) {
return true;
}
return false;
}
}
OrdenarAutor.java
package br.estacio.templateMethod;
public class OrdenarAutor extends OrdenarTemplate {
@Override
public boolean isPrimeiro(Musica musica1, Musica musica2) {
if (musica1.autor.compareToIgnoreCase(musica2.autor) <= 0) {
return true;
}
return false;
}
}
OrdenarEstrela.java
package br.estacio.templateMethod;
public class OrdenarEstrela extends OrdenarTemplate {
@Override
public boolean isPrimeiro(Musica musica1, Musica musica2) {
if (musica1.estrelas>musica2.estrelas) {
return true;
}
return false;
}
}
capítulo 5 • 173
OrdenarNome.java
package br.estacio.templateMethod;
public class OrdenarNome extends OrdenarTemplate {
@Override
public boolean isPrimeiro(Musica musica1, Musica musica2) {
if (musica1.nome.compareToIgnoreCase(musica2.nome) <= 0) {
return true;
}
return false;
}
}
Musica.java
package br.estacio.templateMethod;
public class Musica {
String nome;
String autor;
String ano;
int estrelas;
public Musica(String nome, String autor, String ano, int estrela)
{
this.nome = nome;
this.autor = autor;
this.ano = ano;
this.estrelas = estrela;
}
}
Cliente.java
package br.estacio.templateMethod;
public class Cliente {
public static void main(String[] args) {
Playlist playList = new Playlist(EnumModoReproducao.NOME);
playList.addMusica("Qualquer Coisa", "Caetano Veloso",
"1975", 5);
capítulo 5 • 174
playList.addMusica("Realce", "Gilberto Gil", "1979", 4);
playList.addMusica("Sob Medida", "Chico Buarque", "1995", 3);
playList.addMusica("Faceira", "Gal Costa", "1980", 2);
playList.addMusica("Tenha Calma", "Maria Bethânia", "1989",
1);
System.out.println("| ------------------------ |");
System.out.println("| Lista por Nome de Musica |");
System.out.println("| ------------------------ |");
playList.showLista();
System.out.println("| ------------------------ |");
System.out.println("| Lista por Autor |");
System.out.println("| ------------------------ |");
playList.setModoDeReproducao(EnumModoReproducaoAUTOR);
playList.showLista();
System.out.println("| ------------------------ |");
System.out.println("| Lista por Ano |");
System.out.println("| ------------------------ |");
playList.setModoDeReproducao(EnumModoReproducao.ANO);
playList.showLista();
System.out.println("| ------------------------ |");
System.out.println("| Lista por Estrela |");
System.out.println("| ------------------------ |");
playList.setModoDeReproducao(EnumModoReproducao.ESTRELA);
playList.showLista();
}
}
Visitor
capítulo 5 • 175
Arvore Visitor.java
package br.estacio.visitor;
public interface ArvoreVisitor {
void visitar(No no);
}
ArvoreBinaria.java
package br.estacio.visitor;
public class ArvoreBinaria {
No raiz;
int qtdElementos;
public ArvoreBinaria(int chaveRaiz) {
raiz = new No(chaveRaiz);
qtdElementos = 0;
}
public void addNo(int chave) {
addNo(chave, raiz);
}
public void remover(int chave){
}
public void buscar(int chave){
}
private void addNo(int chave, No no) {
if (no.getChave() == chave)
return;
if (chave>no.getChave()) {
if (no.getDireito() == null) {
no.setDireito(new No(chave));
qtdElementos++;
return;
}
addNo(chave, no.getDireito());
} else {
capítulo 5 • 176
if (no.getEsquerdo() == null) {
no.setEsquerdo(new No(chave));
qtdElementos++;
return;
}
addNo(chave, no.getEsquerdo());
}
}
public void aceitarVisitante(ArvoreVisitor visitor) {
visitor.visitar(raiz);
}
}
No.java
package br.estacio.visitor;
public class No {
protected int chave;
No esquerdo, direito;
public No(intchave) {
this.chave = chave;
esquerdo = null;
direito = null;
}
public String toString() {
return String.valueOf(chave);
}
public int getChave() {
returnchave;
}
public No getEsquerdo() {
returnesquerdo;
}
public void setEsquerdo(No esquerdo) {
this.esquerdo = esquerdo;
}
capítulo 5 • 177
public No getDireito() {
return direito;
}
public void setDireito(No direito) {
this.direito = direito;
}
}
ExibirIdentadoVisitor.java
package br.estacio.visitor;
public class ExibirIndentadoVisitor implements ArvoreVisitor {
@Override
public void visitar(No no) {
if (no == null) {
return;
}
System.out.println(no);
visitar(no.getEsquerdo(), 1);
visitar(no.getDireito(), 1);
}
private void visitar(No no, int qtdEspacos) {
if (no == null) {
return;
}
for (inti = 0; i<qtdEspacos; i++) {
System.out.print("-");
}
System.out.println(no);
visitar(no.getEsquerdo(), qtdEspacos + 1);
visitar(no.getDireito(), qtdEspacos + 1);
}
}
ExibirInOrderVisitor.java
package br.estacio.visitor;
public class ExibirInOrderVisitor implements ArvoreVisitor {
capítulo 5 • 178
@Override
public void visitar(No no) {
if (no == null)
return;
this.visitar(no.getEsquerdo());
System.out.println(no);
this.visitar(no.getDireito());
}
}
ExibirPreOrderVisitor.java
package br.estacio.visitor;
public class ExibirPreOrderVisitor implements ArvoreVisitor {
@Override
public void visitar(No no) {
if (no == null)
return;
System.out.println(no);
visitar(no.getEsquerdo());
visitar(no.getDireito());
}
}
capítulo 5 • 179
ATIVIDADES
01. No exemplo do padrão Façade, foi criada uma interface única de acesso às classes de
sistema. Para facilitar a manutenção do sistema, caso haja uma grande quantidade de clas-
ses e métodos, qual seria uma boa prática para a criação dessa interface?
02. Em um sistema bancário, uma conta corrente pode assumir diversas situações (saldo
positivo, saldo negativo, bloqueado etc.), e as operações na conta sofrerão modificações, de
acordo com o status em que ela se encontra. De acordo com as implementações anteriores,
qual o padrão de projeto recomendado para resolver esse problema? Justifique.
REFERÊNCIAS BIBLIOGRÁFICAS
GAMMA, ERICH et al. Design Patterns: Elements of Reusable Object-Oriented Software.
Addison-Wesley Professional. 1ª Edição. Estados Unidos da América: Addison-Wesley, 1995.
LARMAN, CRAIG. Utilizando UML e Padrões. 3ª Edição. Estados Unidos da América: Prentice Hall,
2007.
FREEMAN,ELISABETH; FREEMAN,ERIC.Use a Cabeça! Padrões de Projetos (design Patterns).
2ª Edição. Estados Unidos da América: Alta Books, 2009.
GABARITO
Capítulo 1
01. Problemas rotineiros, quando devidamente mitigados, podem sugerir uma resolução pa-
dronizada para cada ocorrência. Os padrões de projeto são uma forma de detalhar como
esses problemas podem ser resolvidos.
02. Porque muitas dessas soluções podem sofrer variações, de acordo com aspectos de
técnicos de implementação como linguagem, ambiente de desenvolvimento etc., logo, o im-
portante é transmitir o conceito da solução, e não o meio de construí-la.
capítulo 5 • 180
03. Um exemplo de padrão para e-commerce pode ser a elaboração de um esquema de
carrinho de compras. Usado a estrutura dos padrões, podemos descrever a solução da se-
guinte forma:
• Nome: Carrinho de Compras;
• Problema: Encontrar um meio de registrar os produtos, antes de armazenar no banco
de dados;
• Solução: Criar uma variável de sessão, que armazene uma coleção de objetos produtos,
que possa ser alimentada sempre que o cliente requerer;
• Consequência: Verificar o tempo de vida de variável de sessão. Caso não seja devidamen-
te gerenciada, ela pode expirar e o cliente ficará sem os itens do seu carrinho de compras
para finalizar a operação.
Capítulo 2
03. Abstrair o processo de criação de objetos, ou seja, a sua instanciação. Desta maneira
o sistema não precisa se preocupar com questões sobre, como o objeto é criado, como é
composto, qual a sua representação real.
04. Decorator
Capítulo 4
capítulo 5 • 181
02. O Arquiteto é um profissional que deve, além de conhecer diversos modelos de arqui-
tetura, tem que estar atualizado sobre as mudanças que a computação sofre com o passar
do tempo. Com a evolução das ferramentas e das maneiras de se construir um software, as
responsabilidades desse profissional podem sofrer várias mudanças, mas ainda é pré-maturo
prever a extinção desse papel.
03. A separação de três camadas do modelo MVC deve ser respeitado conceitualmente,
porém, em termos de implementação, naturalmente podem ser inseridas mais camadas, para
atender a alguma particularidade da implementação, como por exemplo, uma camada de
autenticação, porém, a estrutura de separação da visão, do controlador e do modelo têm que
ser respeitada.
04. É recomendável, para que seja mantido o baixo acoplamento entre os sistemas. Cada
sistema possui particularidades que podem variar, mesmo que eles tenham sido desenvolvi-
dos em ambientes idênticos.
05. Sim. Um exemplo seria uma aplicação feito na arquitetura Cliente-Servidor, implemen-
tando MVC.
Capítulo 5
01. Uma prática comum é a de criar várias classes Façade, que contenham os métodos de
um subsistema ou das classes individualmente, dependendo da granularidade de elementos
a ser agrupada.
02. Padrão State. Ele permite que um objeto altere o seu comportamento quando o seu
estado interno muda, e o objeto passará a impressão de ter mudado de classe. O Stateen
capsula os estados em classes separadas e delega as tarefas para o objeto que representa
o estado atual.
03. Em um jogo, onde os botões de um joystick podem assumir diferentes ações, dependen-
do do jogo, por exemplo, em um jogo de futebol, o botão A recebe o comando “Bola Alta()”,
quando o jogador estiver com a bola, ou o comando “Carrinho()”, quando o jogador estiver
sem a bola.
capítulo 5 • 182
ANOTAÇÕES
capítulo 5 • 183
ANOTAÇÕES
capítulo 5 • 184