Buscar

apostila introduão a arquitetura de software

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 91 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 91 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 91 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

LUCIANO GASPAR
ELISAMARA DE OLIVEIRA
Professor autor/conteudista
Atualizado e revisado por
É vedada, terminantemente, a cópia do material didático sob qualquer 
forma, o seu fornecimento para fotocópia ou gravação, para alunos 
ou terceiros, bem como o seu fornecimento para divulgação em 
locais públicos, telessalas ou qualquer outra forma de divulgação 
pública, sob pena de responsabilização civil e criminal.
SUMÁRIO
Apresentação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1 . Fundamentos de arquitetura de software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1. Definição de arquitetura de software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6
1.2. Modelagem de aplicações de softwares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7
1.3. Tarefas acidentais e essenciais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9
1.4. Aspectos essenciais na produção de software. . . . . . . . . . . . . . . . . . . . . . . . . . . . .11
1.5. Princípios SOLID. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17
1.5.1. Princípio de Responsabilidade Única . . . . . . . . . . . . . . . . . . . . . 19
1.5.2. Princípio Aberto-Fechado . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.5.3. Princípio de Substituição de Liskov . . . . . . . . . . . . . . . . . . . . . . 22
1.5.4. Princípio de Segregação de Interface. . . . . . . . . . . . . . . . . . . . . 23
1.5.5. Princípio de Inversão de Dependência . . . . . . . . . . . . . . . . . . . . 23
2 . Padrões de arquitetura de software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.1. Definição de padrão arquitetural . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.2. Padrão de arquitetura em camadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Padrão de arquitetura Pipes and filters ou Pipeline . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.4. Padrão de arquitetura Blackboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.5. Model-View-Controller (MVC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Padrão de arquitetura Microkernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.7. Padrão de arquitetura Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3 . Design patterns – Padrões de criação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.1. Conceitos de padrões de projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.2. Definição de padrões de criação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .52
3.3. Padrão Abstract Factory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.4. Padrão Builder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.5. Padrão Factory Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.6. Padrão Prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.7. Padrão Singleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4 . Design patterns – Padrões estruturais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.1. Definição de padrões estruturais. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.2. Padrão Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.3. Padrão Bridge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4.4. Padrão Decorator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.5. Padrão Façade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.6. Padrão Proxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
5 . Design patterns – Padrões comportamentais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
5.1. Definição de padrões comportamentais. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .75
5.2. Padrão Chain of Responsability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
5.3. Padrão Mediator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
5.4. Padrão Observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.5. Padrão Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.6. Padrão Visitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Considerações finais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Glossário de Siglas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Glossário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Bibliografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Pág. 5 de 91
APRESENTAÇÃO
Os sistemas de informação são provedores de solução para as mais diversas áreas do conhecimento 
e impulsionam a indústria, o comércio, os serviços e, em especial, os segmentos de mercado 
dependentes de tecnologia ou mesmo novos negócios que surgem apoiados em software. Segundo 
Laudon (2010), as empresas apoiam seus processos de gestão nas tecnologias, com o objetivo de 
gerenciar suas operações, desenvolver novos produtose serviços, estreitar o relacionamento com 
clientes e fornecedores, auxiliar na tomada de decisões e obter vantagem competitiva.
A importância crescente do software, aliado ao maior conhecimento (desde 1967) sobre como 
construí-lo, resultou na necessidade de uma formação mais ampla para o programador. Este 
deve se preocupar em aplicar técnicas e métodos especializados para projetar, construir, testar e 
manter os produtos de software. Uma parte considerável destes conhecimentos pertence à área 
de engenharia de software.
Após a “crise do software”, uma longa série de inovações passou a ser adotada nas práticas 
de desenvolvimento, incluindo modularidade, programação estruturada, diagramas de fluxo de 
dados, proteção de informações, information hiding, abstração de dados, reutilização de software, 
programação visual, programação orientada a objeto (POO), padrões de projetos e ferramentas 
CASE (Computer-aided Software Engineering). Porém, tudo isso trouxe ganhos modestos e não 
transformou a engenharia de software em algo sistemático, disciplinado e quantificável para o 
desenvolvimento, a operação e a manutenção do software.
A engenharia de software possui peculiaridades que talvez nenhuma outra área do conhecimento 
tenha. Isso nos faz refletir sobre quais competências um profissional que atue em desenvolvimento 
de sistemas de software tenha que adquirir.
Assim, prezado aluno, este material foi elaborado para chamar sua atenção e proporcionar uma 
reflexão sobre os principais aspectos que têm afetado diretamente a produção do software. Além 
disso, vamos apontar os princípios ligados à arquitetura e aos padrões de projeto que podem ser 
seguidos, de forma a trazer um diferencial na carreira do desenvolvedor de soluções em software, 
pois o conhecimento das dificuldades inerentes a esta área tornará mais fácil o trabalho quando 
elas surgirem.
Luciano Gaspar
Elisamara de Oliveira
Pág. 6 de 91
1. FUNDAMENTOS DE ARQUITETURA DE SOFTWARE
Primeiramente, abordaremos conceitos iniciais sobre o projeto de arquitetura de software e as 
consequências de um software não arquitetado. Será discutido o papel do arquiteto de software, 
assim como as barreiras e os princípios de modelagem que devem ser levados em consideração 
na concepção de uma arquitetura.
1.1. Definição de arquitetura de software
Para entendermos a necessidade de se arquitetar um software, alguns conceitos devem ser 
apresentados, bem como os desafios com os quais um profissional desta área deve lidar.
Historicamente, os fracassos de projetos de softwares são significativos. De acordo com Hastie 
e Wojewoda (2015), o Chaos Report da Gartner de 2015 mostra que apenas 29% dos projetos foram 
bem sucedidos, 52% chegaram ao final ainda necessitando de ajustes e 19% falharam. Os fatores 
críticos de sucesso estão relacionados à natureza complexa e intangível do software.
O software é visto pelas áreas de negócios como algo flexível e adaptável, porém sabemos que 
um software não arquitetado pode dificultar sua manutenção, escalabilidade e reúso.
Desta forma, desenvolver soluções arquitetadas é uma prática que tornará nosso trabalho, a 
longo prazo, menos reativo e estressante.
Mas o que é arquitetura de software?
IMPORTANTE
Bass et al. (2003) definem arquitetura de software como a estrutura do sistema composta por 
elementos de software (componentes, conectores ou dados), com propriedades externamente visíveis 
destes elementos e os relacionamentos entre eles.
Uma arquitetura registra informações sobre como os elementos de software se relacionam 
uns com os outros, ocultando ou explicitando elementos do software que devem ou não existir em 
diferentes níveis de abstração.
As figuras 1 e 2 ilustram um projeto arquitetado e um não arquitetado. Reflita sobre as principais 
características entre eles.
Pág. 7 de 91
Figura 1 – Bairro planejado
Fonte: Struvictory/Shutterstock
Figura 2 – Crescimento desordenado
Fonte: Donatas Dabravolskas/Shutterstock
REFLITA
Os softwares que estamos desenvolvendo são mais parecidos com a figura 1 ou com a figura 
2? Nossas aplicações possuem um padrão arquitetural? São concebidos para aceitar novas 
funcionalidades? Permitem o reúso e a escalabilidade?
Aqueles que possuem vivência na área de desenvolvimento de software sabem que, muitas 
vezes, uma mudança ou um novo requisito tem impacto estrutural e demanda grande esforço de 
desenvolvimento e, se realizado sem planejamento, desencadeia efeitos colaterais em todo o software.
1.2. Modelagem de aplicações de softwares
Como você já deve ter estudado, um aplicativo de software possui um ciclo de vida. Ao longo 
deste ciclo, muitas mudanças são realizadas e geram impactos no código escrito nas primeiras 
versões do software.
O software é afetado por um fenômeno de degradação que impacta sua confiabilidade, 
estrutura e sua consistência. Sua documentação fica desatualizada, dificultando sua manutenção 
e tornando-a onerosa.
Sabemos que um processo de desenvolvimento definido que favoreça a obtenção e a validação 
dos requisitos pode minimizar esses impactos, porém o fato de o software ser visto como algo 
flexível torna a definição de uma arquitetura um elemento fundamental para o desenvolvimento 
de software em larga escala.
Pág. 8 de 91
Se você já desenvolveu algum software ou até mesmo uma planilha eletrônica com várias 
referências a fórmulas em diferentes arquivos, já percebeu que existe um limite para a capacidade 
humana para compreender, ao longo do tempo, aquilo que foi produzido, tornando esta uma 
atividade complexa.
O software possui uma natureza complexa crescente, seja pelo número de linhas de código ou 
pela sua intangibilidade. Logo, a criação de modelos torna-se indispensável para compreensão do 
que está sendo desenvolvido.
O uso de modelos apoia o entendimento e a definição da arquitetura do software, assim como 
a identificação das regiões críticas que podem sofrer degradação ao longo do tempo.
No processo de criação de modelos, muitos problemas podem ser antecipados e decisões são 
tomadas a fim de minimizar seu impacto ao longo do tempo.
IMPORTANTE
Blaha e Rumbaugh (2006, p. 17) definem modelo como uma abstração de algo que facilita seu 
entendimento antes de construí-lo. Abstração é um processo mental básico que permite lidar com a 
complexidade, omitindo detalhes não essenciais.
A abstração permite a simplificação de algo complexo, como no exemplo na figura 3.
Figura 3 – Abstração de uma casa
Fonte: Melissa King/Shutterstock.com
Pág. 9 de 91
No processo de produção do software, modelos são criados para descrever a estrutura e o 
comportamento de um software para posterior implementação. Estas descrições de modelos guiam 
a construção e mantêm registros das decisões tomadas na sua concepção.
Para os criadores da Unified Modeling Language (UML), Booch, Rumbaugh e Jacobson, nenhum 
modelo único é suficiente. Qualquer sistema não trivial será mais bem investigado por meio de um 
conjunto de modelos quase independentes com vários pontos de vista.
Um ou mais modelos podem servir de inspiração para dar origem a uma arquitetura que sustente 
as necessidades do que está sendo modelado.
IMPORTANTE
De acordo com Zachman (1997),
Arquitetura é o conjunto de artefatos ou um descritivo relevante de um objeto, de 
forma que este possa ser construído de acordo com os requisitos (de qualidade), 
bem como mantido ao longo da sua vida útil.
Neste sentido, modelar um sistema significa determinar e representar um conjunto 
de informações arquitetadas sob diferentes vistas que servirão de guia de referência 
para a produção de algo concreto (código-fonte).
Cada área de conhecimento adota tipos específicos de modelos. Na engenharia de software 
contemporânea, segundo Booch, Rumbaugh e Jacobson (2006), adota-se uma perspectiva orientada 
a objetos, onde a UML é empregada para visualização, especificação, construção e documentação 
de artefatos que orientamo desenvolvimento do software.
Para entender a importância de controlar esta complexidade, vamos analisar no próximo tópico 
o trabalho de Brooks (1987), que faz uma classificação dos aspectos que estão sob nosso controle 
e aqueles que fogem dele, impactando o cronograma, o custo e a equipe de projeto do software.
1.3. Tarefas acidentais e essenciais
Independentemente do processo de desenvolvimento de software adotado, um conjunto de 
tarefas é organizado e realizado. Tais tarefas são classificadas por Brooks (1987) como tarefas 
acidentais e essenciais:
• As tarefas acidentais estão relacionadas à implementação do software e as principais 
preocupações estão ligadas à sintaxe das linguagens, aos limites de hardware, aos ambientes e 
Pág. 10 de 91
ferramentas de desenvolvimento e a demais aspectos técnicos. Estes aspectos são facilmente 
superados com treinamentos, leituras ou por meio de consulta a um profissional mais experiente.
• As tarefas essenciais estão relacionadas ao processo mental de criação de um conjunto de 
conceitos que se interligam.
Tanto as tarefas acidentais quanto as essenciais criam barreiras para o desenvolvimento de 
software, porém grande parte das barreiras acidentais foi transposta na última década e as principais 
falhas de projetos estão relacionadas às atividades essenciais que criam barreiras que dificilmente 
são domináveis.
Figura 4 – Atividades essenciais e seu peso
Fonte: iQoncept/Shutterstock
De forma análoga, e neste contexto, pode-se comparar o processo de desenvolvimento de 
software ao processo de criação de um texto, em que as tarefas acidentais estão relacionadas ao 
domínio de uma ferramenta de edição de textos, a sintaxe e a semântica da língua. Tais tarefas 
podem criar barreiras para a produção do texto, mas serão superadas com algum nível de estudo 
ou apoio de terceiros, porém não garantem que o texto escrito atenderá critérios de qualidade.
Logo, o domínio de tarefas acidentais não garante a qualidade do que está sendo produzido. A 
qualidade será definida pela forma peculiar de criação e organização das ideias atuando sobre a 
construção mental e essencial que será descritos de forma textual.
Pág. 11 de 91
1.4. Aspectos essenciais na produção de software
Brooks (1987) elenca quatro aspectos essenciais que impactam na produção do software. 
São eles: complexidade, conformidade, flexibilidade e intangibilidade. Estes aspectos são 
descritos a seguir.
Complexidade
Entidades de software possuem uma natureza complexa. Assim, aumentar sua escala não é 
meramente repetir os mesmos elementos em tamanho maior. É necessário um aumento do número 
de elementos diferentes, amplificando a complexidade do todo de forma não linear.
Queremos dizer que existe uma grande diferença entre fazer um software com poucas linhas 
de código e desenvolver um software com um número maior de requisitos.
Para um software mais robusto, não basta aumentar as linhas de código. É necessário incluir 
elementos de software para facilitar o entendimento das linhas já produzidas, a manutenção, a 
inclusão de novas funcionalidades, o aumento da equipe, a padronização e a inclusão de interfaces, 
entre outras demandas exigidas por um software de maior escala.
Imagine um artesão trabalhando na produção de um vaso de barro. Você, de passagem em 
turismo pelo local, adorou aquele vaso. Em função disso, solicitou ao artesão que produzisse 1.000 
unidades, pois presentearia seus familiares e venderia o restante dos vasos na sua cidade de origem.
Figura 5 – Artesão trabalhando na produção de um vaso
Fonte: Thirteen/Shutterstock
Pág. 12 de 91
REFLITA
O processo e as ferramentas de produção adotados pelo artesão seriam suficientes para atender sua 
encomenda? Bastaria apenas aumentar em quantidade a matéria-prima do artesão? Contratar mais 
artesões garantiria a beleza do vaso apreciada por você? O processo para produzir uma unidade é o 
mesmo para produzir 1.000 unidades?
Acredito que chegará facilmente à conclusão que novos elementos deverão ser inseridos no 
processo de produção do vaso. Talvez o uso de formas para garantir o padrão, a contratação de 
novos artesões, uma sequência ordenada de tarefas, a criação de modelos que serão submetidos 
a testes, entre outras ações.
AGORA, REFLITA:
O que diferencia a produção de um software de 1.000 linhas de código com um de 15.000 linhas? Será 
só a quantidade de linhas?
Softwares com 1.000 linhas de código, no pior caso, podem ser refeitos gastando apenas mais 
alguns dias de trabalho; entretanto, reescrever um sistema mais complexo levaria meses ou anos. 
Portanto, cuidar da arquitetura no início reduz os problemas futuros.
A figura 6 exibe os impactos da 
complexidade na produção do software. Da 
complexidade, vem a dificuldade de entender 
e se comunicar com os membros da equipe 
de desenvolvimento, levando à deficiência 
do produto, que aumenta os custos e 
afeta o cronograma e a confiabilidade. Da 
complexidade da estrutura, surge também 
a dificuldade de entender o comportamento 
e ampliar os programas sem criar efeitos 
colaterais, tornando árduo o gerenciamento 
destes problemas.
Figura 6 – Impactos da complexidade no 
desenvolvimento de software
1
complexidade
2
Comunicação
7
Falta de 
Con�abilidade
6
Di�culdade de 
entender
5
Atraso de
Crono-
grama
4
Aumento
dos
custos
3
De�ciência 
do Produto 
Fonte: Elaborado pelo autor.
Pág. 13 de 91
Provavelmente, muitos dos programadores já passaram por situações em que não conseguiram 
ou demoraram para entender um código, seja ele gerado por terceiros ou até mesmo um código 
próprio.
Segundo Brooks (1987), a complexidade do código é crescente e existe um limite que o cérebro 
humano consegue gerenciar, impactando na quantidade de novas linhas de código que podem ser 
acrescentadas a um programa ao longo do tempo.
A figura 7 mostra a relação produtividade no desenvolvimento versus tempo. À medida que o 
software é implementado, ou seja, linhas de código são inseridas, sua complexidade cresce e afeta 
a produtividade ao longo do tempo.
Figura 7 – Tempo versus produtividade
100
80
60
40
20
0
Pr
od
ut
iv
id
ad
e
Tempo
Fonte: Martin (2009).
Conformidade e flexibilidade
Outras áreas do conhecimento também lidam com a complexidade crescente, mas como o 
software não está suscetível às leis naturais, é visto como algo flexível e de fácil adequação, ao 
menos se comparado à Física e outras ciências.
Brooks (1997) afirma que, em decorrência da sua complexidade, a versão inicial de um software 
muitas vezes não atende aos requisitos na sua plenitude, necessitando de constantes mudanças, de 
tal modo que todo software de sucesso acaba sendo modificado. Assim, um sistema de software 
deve ser concebido para mudar.
Pág. 14 de 91
Caso você já atue na área de desenvolvimento de software, deve ter percebido que a mudança 
dos requisitos é algo constante. Isso não significa que as mudanças são correções de erros, mas 
podem decorrer de novas funcionalidades para atender às necessidades de negócios. Vale dizer que 
a TI deve impulsionar os negócios e não ser um gargalo para novas oportunidades. Logo, precisamos 
desenvolver softwares nos quais uma mudança não afete toda a estrutura já desenvolvida.
Nosso código deve “aceitar” mudanças com certa flexibilidade, comunicar claramente suas 
responsabilidades, facilitar a manutenção e proporcionar o reúso. Esse é o grande desafio!
Intangibilidade
Softwares são intangíveis, portanto, é difícil criar uma representação visual objetiva e comum 
para eles. Ao tentar diagramar uma estrutura de software, descobre-se que ela não é apenas um, 
mas sim vários diagramas superpostos uns aos outros, sem hierarquias ou relações diretas entre 
seus elementos, forçando cortes que eliminam conexões nas diferentes vistas do modelo.
Para Brooks (1987), esses cortes prejudicam não só o processo de projeto do software, mas 
também a comunicação entre osmembros da equipe.
A UML é uma poderosa ferramenta capaz de tangibilizar as descrições de implementação do 
arquiteto de software.
Figura 8 – UML
Fonte: dizain/Shutterstock
Pág. 15 de 91
Um arquiteto de software deve apoiar-se em descrições de modelos para comunicar suas 
decisões de implementação. Um diagrama UML, analogamente, pode ser comparado com uma 
planta hidráulica ou elétrica que um engenheiro civil ou eletricista utiliza para tangibilizar um modelo 
mental e comunicar seu projeto.
Portanto, a descrição de modelos de software apoiados em diagramas é uma ferramenta 
essencial para um arquiteto de software e um dos elementos que o difere do programador.
ACONTECEU
UML: um breve histórico
A UML surgiu da união de três metodologias de modelagem: o método do americano Grady Booch, o 
método OMT (Object Modeling Technique), do sueco Ivar Jacobson, e o método OOSE (Object-oriented 
Software Engineering) do americano James Rumbaugh. Estas eram, até meados da década de 1990, 
as três metodologias de modelagem orientada a objeto mais populares. A união dessas tecnologias 
contou com o apoio da Rational Software, que incentivou e financiou a união das três metodologias. 
O esforço inicial do projeto começou com a união do método de Booch com o de Jacobson, o que 
resultou no lançamento do método unificado no final de 1995. Logo em seguida, Rumbaugh juntou-
se a Booch e Jacobson na Rational Software, e seu método OOSE começou a ser incorporado à nova 
metodologia. O trabalho de Booch, Jacobson e Rumbaugh, conhecidos popularmente como “os três 
amigos”, resultou no lançamento, em 1996, da primeira versão da UML propriamente dita.
Assim que a primeira versão foi lançada, diversas grandes empresas atuantes na área de software 
passaram a contribuir com o projeto, fornecendo sugestões para melhorar e ampliar a linguagem. 
Finalmente, a UML foi adotada pela OMG (Object Management Group), em 1997, como a linguagem 
padrão de modelagem.
Fonte: Guedes (2014, p. 15-16).
Quadro 1 – Classes, objetos e métodos
O que é orientação a objetos (OO)
O termo orientado a objetos (OO) significa que organizamos o software como uma coleção de objetos 
distintos, que incorporam estruturas de dados e comportamentos. Isso é diferente das técnicas 
de programação procedural, nas quais as estruturas de dados e o comportamento estão pouco 
conectados. A programação OO insere novos conceitos no desenvolvimento de software como, por 
exemplo, classes, objetos e métodos.
Pág. 16 de 91
Classes, objetos e métodos
Classes são representações de um conjunto de objetos com características particulares. A classe é 
definidora do comportamento dos objetos por meio de seus métodos e dos estados que o objeto é 
capaz de manter por meio de seus atributos. Numa classe de nome Motor, por exemplo, a propriedade 
Ligar pode ser definida como um de seus atributos.
Um objeto é uma representação, por meio de uma classe, de algo que pode ser instanciado e utilizado 
para interagir com outros objetos em tempo de execução. O objeto pode armazenar um estado por 
meio de seus atributos e reagir a mensagens enviadas a ele por outros objetos, assim como pode se 
relacionar e enviar mensagens a outros objetos.
Métodos são as definições de possibilidades de execução de ações de objetos. Esta ação que é 
definida no método só ocorre quando for invocada por outro objeto. Um objeto definido por meio de 
uma classe pode conter diversos métodos. Ao ser criada uma classe de um objeto Transporte, por 
exemplo, a instância Carro pode criar os métodos Abastecer, Andar, Estacionar etc.
Fonte: Blaha e Rumbaugh (2006, p. 1).
Polimorfismo e herança em OO
Polimorfismo significa que a mesma operação pode atuar de modos diversos em classes diferentes. 
Uma operação é uma ação ou transformação que um objeto executa ou a que ele está sujeito. Right-
justify (justificar à direita), display (exibir) e move (mover) são exemplos de operações. A operação 
move (mover), por exemplo, pode atuar de modo diferente nas classes Janela e Peça de Xadrez.
Uma implementação específica de uma operação por uma determinada classe é chamada de método. 
Quando uma operação baseada em objetos é polimórfica, pode haver mais de um método para a sua 
implementação.
No mundo real, uma operação é simplesmente uma abstração de um comportamento análogo entre 
diferentes tipos de objetos. Cada objeto “sabe” como executar suas próprias operações. Entretanto, 
uma linguagem de programação baseada em objetos seleciona automaticamente o método correto 
para implementar uma operação com base no nome da operação e na classe do objeto que esteja 
sendo operado. O usuário de uma operação não precisa saber quantos métodos existem para 
implementar uma determinada operação polimórfica. Novas classes podem ser adicionadas sem 
que se modifique o código existente, pois são fornecidos métodos para cada operação aplicável nas 
novas classes.
Herança é o compartilhamento de atributos e operações entre classes com base num relacionamento 
hierárquico. Uma classe pode ser definida de forma abrangente e depois ser refinada em sucessivas 
subclasses mais definidas. Cada subclasse incorpora ou herda todas as propriedades da sua 
superclasse e acrescenta suas próprias e exclusivas características. As propriedades da superclasse 
não precisam ser repetidas em cada subclasse. Por exemplo: Janela Rolante e Janela Fixa são 
subclasses da superclasse Janela. Estas duas subclasses herdam as propriedades de Janela, como 
uma região visível na tela. Janela Rolante acrescenta uma barra de rolagem e limites de rolagem. A 
capacidade de identificar propriedades comuns a várias classes de uma superclasse comum e de 
fazê-las herdarem as propriedades da superclasse pode reduzir substancialmente as repetições nos 
projetos e programas, sendo uma das principais vantagens dos sistemas baseados em objetos.
Fonte: Blaha e Rumbaugh (2006, p 2).
Pág. 17 de 91
1.5. Princípios SOLID
Em 1995, Robert C. Martin iniciou uma discussão sobre um conjunto de princípios de modelagem 
de software orientado a objetos. Estes princípios ajudavam a lidar com os problemas oriundos da 
natureza do software discutidos até aquele momento.
Booch, Rumbaugh e Jacobson (2005, p. 135) definem que, em OO, “responsabilidade é um contrato 
ou obrigação de um tipo ou classe”. Os autores afirmam que há dois tipos de responsabilidades 
dos objetos:
• De conhecimento (knowing): sobre dados privativos e encapsulados; sobre objetos relacionados; 
sobre coisas que pode calcular ou derivar.
• De realização (doing): em fazer algo em si mesmo; iniciar uma ação em outro objeto; controlar 
e coordenar atividades em outros objetos.
Responsabilidades são atribuídas aos objetos durante o projeto do software OO. A tradução de 
responsabilidades em classes e métodos depende da granularidade da responsabilidade. Os métodos 
são implementados para cumprir responsabilidades. Uma responsabilidade pode ser cumprida por 
um único método ou por uma coleção de métodos trabalhando em conjunto. Responsabilidades 
do tipo knowing geralmente são inferidas a partir do modelo conceitual (são os atributos e os 
relacionamentos).
Figura 9 – Object-oriented Programming (OOP)
Fonte: Bobicova Valeria/Shutterstock
Pág. 18 de 91
Um dos pontos que levam à degradação do código ao longo do tempo é o alto acoplamento entre 
os objetos (que é o foco), o qual deve ser gerenciado, de modo a reduzir a dependência entre eles.
No paradigma orientado a objetos, uma das principais preocupações é o acoplamento . Um 
acoplamento pode ocorrer de diferentes formas:
• quando uma classe A possui um atributo que referencia o objeto B ou a própria classe B;
• quando um objeto A chama um método de um objeto B;
• quando um objeto A tem um método que referencia um objeto B ou a própria classe B, tipicamente 
caracterizado por um parâmetro ou variável local do tipo B ou um objeto retornado de uma 
mensagem sendo uma instância de B.
Tais formas de acoplamento podemser mitigadas com mudanças no código-fonte. Uma boa 
prática no desenvolvimento de software OO é criar estruturas com baixo acoplamento entre objetos, 
para que a atribuição de responsabilidades seja feita de forma que sua alocação não aumente o 
acoplamento de um objeto com outros.
Ainda dentro de um projeto OO, existe outro conceito muito importante: a coesão. Ela é uma medida 
de quão fortemente estão relacionadas e focadas as responsabilidades de um dado elemento. Um 
elemento que esteja altamente especializado e que não realize uma grande quantidade de tarefas 
é considerado com alta coesão, ou seja, possui um alto grau de coesão.
Assim, uma classe com baixa coesão geralmente executa muitas funções pouco relacionadas 
entre si, realizando um trabalho excessivo. Classes deste tipo são altamente indesejáveis em um 
projeto, pois acumulam os seguintes problemas:
• são de difícil compreensão;
• não conseguem ser reutilizadas;
• são de difícil manutenção;
• são constantemente afetadas por qualquer modificação no projeto.
IMPORTANTE
Baixo acoplamento (low coupling) e alta coesão (high cohesion) são conceitos relevantes que devem 
ser considerados e preservados sempre durante os processos de tomada de decisão em um projeto 
orientado a objetos. Estão intimamente ligados ao desenvolvimento de softwares que priorizam uma 
arquitetura que favorece a manutenção e a construção de objetos reusáveis.
Pág. 19 de 91
O gerenciamento de dependência entre objetos é um problema que certamente já foi enfrentado 
por quem desenvolve ou desenvolveu um aplicativo OO. Não se preocupar com o gerenciamento 
de dependência leva a um código confuso, difícil de mudar e não reutilizável.
Os princípios a seguir concentram-se na gestão de dependências dos objetos de um sistema 
OO e são conhecidos como SOLID. São estes os princípios SOLID:
• S – Single Responsability Principle (Princípio de Responsabilidade Única)
• O – Open/Closed Principle (Princípio Aberto-Fechado)
• L – Liskov Substitution Principle (Princípio de Substituição de Liskov)
• I – Interface Segregation Principle (Princípio de Segregação de Interface)
• D – Dependency Inversion Principle (Princípio da Inversão de Dependência)
Figura 10 – Princípios SOLID
Princípios
S.O.L.I.D.
Fonte: <https://www.quora.com/How-do-I-write-PHP-code-that-easy-to-maintain-and-upgrade>.
Cada um destes princípios será detalhado a seguir.
1.5.1. Princípio de Responsabilidade Única
O Princípio de Responsabilidade Única, também conhecido como Single Responsability Principle 
(SRP) estabelece que uma classe deve ter um e somente um motivo para mudar.
Se uma classe é responsável por efetuar várias ações dentro de um determinado contexto, ela 
está ferindo este princípio.
Vamos analisar o exemplo:
Pág. 20 de 91
A classe Retângulo, da figura 11 possui os métodos Área, que calcula a área do retângulo, e 
Desenhar, que desenha o retângulo. Essa classe fere o princípio SRP, pois se a forma de cálculo 
for alterada ou uma interação com a interface gráfica tiver que ser alterada, ambas afetam a 
classe Retângulo. Ou seja, as linhas de código escritas nesta classe possuem duas formas de 
serem impactadas.
Figura 11 – Classe Retângulo
Retângulo
+ Área ()
+ Desenhar () 
Fonte: Elaborado pelo autor.
Para atender o princípio SRP, devemos separar as responsabilidades em duas classes diferentes, 
sendo uma para calcular a área e outra para desenhar o retângulo. Neste caso, teremos as classes 
RetânguloDes e RetânguloCal, cada uma com seus métodos, conforme mostra a figura 12.
Figura 12 – Classes para cálculo da área e desenho de retângulos
RetânguloDes
+ Desenhar ()
RetânguloCal
+ Area()
Fonte: Elaborado pelo autor.
1.5.2. Princípio Aberto-Fechado
O Princípio Aberto-Fechado, ou simplesmente Open/Closed Principle (OCP), estabelece que 
uma classe deve estar “aberta” para extensão, porém fechada para modificação, ou seja, devemos 
Pág. 21 de 91
organizar as classes para possibilitar o crescimento, porém sem alterar o código das classes 
existentes.
Vejamos o exemplo da figura 13.
Figura 13 – Classe Pagamento
+ Parcelado ()
+ À Vista ()
+ Débito ()
+ Crédito ()
Pagamento
Fonte: Elaborado pelo autor.
A classe Pagamento possui os métodos que têm as instruções para pagamentos dos tipos 
Parcelado, À Vista, Débito e Crédito. Como você implementaria isso?
Certamente, em determinado trecho de código, seria utilizada uma instrução IF ou CASE 
e, de acordo com a forma de pagamento selecionada pelo usuário, seria chamado um método 
específico. Caso você venha desenvolvendo softwares desta forma, lembre-se que o princípio 
OCP está sendo ferido.
O resultado em não respeitar este princípio é que, para cada nova forma de pagamento, o código 
da classe Pagamento deverá ser alterado com a inclusão do novo método de pagamento e a inclusão 
de mais um parâmetro na instrução IF ou CASE.
Para atender o princípio OCP, é necessário separar as formas de pagamento em subclasses. 
Desta forma, uma nova forma de pagamento não afetaria a classe Pagamento, ou seja, o código 
estaria fechado para alteração e aberto para extensão.
Pág. 22 de 91
A figura 14 ilustra as classes, simplificadamente, para atender o OCP, neste exemplo.
Figura 14 – Classes e subclasses para formas de pagamento
Pagamento
Parcelado À Vista Débito Crédito
Fonte: Elaborado pelo autor.
Aplicando o Princípio Aberto-Fechado, os problemas apontados são evitados, porque a classe 
Pagamento não precisa mais ser alterada quando uma nova forma de pagamento for inserida. Neste 
caso, deve ser feita a inclusão de uma subclasse, com a nova forma de pagamento e os métodos 
específicos deste tipo de pagamento.
Desta forma, as classes serão mais simples se não estiverem sobrecarregadas de atribuições.
1.5.3. Princípio de Substituição de Liskov
O Princípio de Substituição de Liskov, ou simplesmente Liskov Substitution Principle (LSP), 
estabelece que as classes derivadas devem ser substituídas por suas classes base.Se utilizarmos um 
objeto e, com o uso de polimorfismo, manipulá-lo como sendo do seu tipo base, ele deve funcionar 
e se comportar da mesma forma como se comportaria se realmente fosse daquele tipo.
Retomando o exemplo ilustrado na figura 14 temos uma classe Pagamento (base) e subclasses 
derivadas (Parcelado, À Vista, Débito e Crédito). Respeitar o princípio LSP significa dizer que posso 
usar qualquer classe derivada como se fosse a classe base Pagamento, sem alterar o comportamento 
da classe base.
Pág. 23 de 91
1.5.4. Princípio de Segregação de Interface
O Princípio de Segregação de Interface ou Interface Segregation Principle (ISP) estabelece que 
interfaces sejam de “fina granularidade”, para que sejam específicas para quem vai utilizá-las. Uma 
interface não deve ter inúmeras funcionalidades. Deve ser a mais “enxuta” possível, seguindo o 
princípio SRP, porém voltado para as interfaces.
Figura 15 – Princípio de Segregação de Interface
Fonte: <https://lostechies.com/derickbailey/2009/02/11/solid-development-principles-in-motivational-pictures/>.
1.5.5. Princípio de Inversão de Dependência
Com o objetivo de reduzir o acoplamento entre objetos, o Princípio de Inversão de Dependência 
ou Dependency Inversion Principle (DIP) estabelece que sempre devemos depender de classes 
abstratas e nunca de classes concretas. Se um objeto depender de classes concretas, qualquer 
alteração que ocorrer nesta classe afeta todas que dependerem dela. Observe a figura 16, elaborada 
com o software BlueJ (www.bluej.org), que mostra quatro classes distintas, cuja relação ocorre na 
forma de classes concretas.
Pág. 24 de 91
Figura 16 – Relação entre classes
Canvas
Circle
Square
Triangle
Fonte: Elaborado pelo autor.
A figura 17 representa, por meio de marcações hachuradas, as classes que são afetadas quando 
a classe Canvas é alterada. Observe que uma alteração em Canvas afeta todas as demais classes 
relacionadas a ela.
Figura 17 – Classes afetadasapós alteração em Canvas
Canvas
Circle
Square
Triangle
Fonte: Elaborado pelo autor.
Pág. 25 de 91
A figura 18 representa uma implementação em que existe uma relação entre as classes, porém 
todas dependem da classe abstrata Figure. Observe que esta classe impede a propagação da 
alteração realizada em Canvas.
Figura 18 – Diagrama com classe abstrata
Canvas
Circle
Square
Triangle
<<abstract>>
Figure
Fonte: Elaborado pelo autor.
SAIBA MAIS
Caro aluno, veja mais exemplos de códigos com aplicação de princípios SOLID em Marabesi (2016), 
disponível em: https://marabesi.com/oop/2016/04/12/s-o-l-i-d.html > e Oloruntoba (2015), disponível em: 
https://scotch.io/bar-talk/s-o-l-i-d-the-first-five-principles-of-object-oriented-design >.
Pág. 26 de 91
2. PADRÕES DE ARQUITETURA DE SOFTWARE
Neste capítulo, descreveremos os padrões arquiteturais. Alguns exemplos de aplicação serão 
apresentados, bem como os benefícios de sua utilização em diferentes casos.
2.1. Definição de padrão arquitetural
Um padrão arquitetural determina a estrutura de um projeto de software. Portanto, trata-se de 
um conceito amplo que aborda questões como limitação de hardware, alta disponibilidade de uso 
e risco de negócio (BUSCHMANN et al., 2001).
Como sabemos, o desenvolvimento de algoritmos visa resolver problemas com o auxílio do 
computador. Já houve uma época em que os programadores tinham muita dificuldade com a escrita 
e a compilação do código. No entanto, esta dificuldade já foi superada com a ajuda de ferramentas 
que auxiliam o programador na sintaxe e semântica das linguagens de programação.
Temos agora um problema de segunda ordem que está relacionado a como organizar as linhas 
de código.
Muitas vezes, sabemos quais linhas de código atenderão um determinado requisito de negócio, 
porém ainda precisamos saber qual a melhor organização das linhas de código que evitará a 
degradação da aplicação.
Figura 19 – Planta de uma casa
Fonte: Franck Boston/Shutterstock
O uso de padrões arquiteturais pode ser um dos 
direcionadores desta organização. Um único padrão 
pode auxiliar na solução das necessidades ligadas 
à organização do código, contudo, é possível usar 
uma combinação de padrões.
Vale lembrar que o conceito de padrões 
arquiteturais diferencia-se de padrões de projetos 
e ambos são assuntos tratados neste material.
Pág. 27 de 91
IMPORTANTE
Arquitetura de software, segundo Booch, Rumbaugh e Jacobson (2005, p. 34) é o “conjunto de 
decisões significativas” acerca dos seguintes itens:
• a organização do sistema de software;
• a seleção dos elementos estruturais e suas interfaces, que compõem o sistema;
• seu comportamento, conforme especificado nas colaborações entre esses elementos;
• a composição desses elementos estruturais e comportamentais em subsistemas 
progressivamente maiores;
• o estilo de arquitetura que orienta a organização: os elementos estáticos e dinâmicos e suas 
respectivas interfaces, colaborações e composição.
De uma maneira mais simplificada, Pressman (2011, p. 230) define arquitetura de software como 
a “estrutura do sistema que abrange os componentes de software, as propriedades externamente 
visíveis destes componentes e as relações entre eles”. O autor ainda completa que a arquitetura
[...] não é o sistema operacional, mas sim uma representação que nos permite (1) 
analisar a efetividade do projeto no atendimento aos requisitos declarados, (2) 
considerar alternativas de arquitetura em um estágio quando realizar mudanças de 
projeto ainda é relativamente fácil e (3) reduzir os riscos associados à construção 
do software.
As seções a seguir descrevem os principais padrões arquiteturais, suas vantagens e desvantagens. 
Vale lembrar que existem muitos outros padrões possíveis, simples ou compostos, mas vamos nos 
ater aos mais utilizados nesta abordagem.
2.2. Padrão de arquitetura em camadas
De acordo com Buschmann et al. (2001), camadas são grupos de componentes reutilizáveis, 
similares e inter-relacionados, responsáveis por um nível de abstração particular, ou seja, as camadas 
executam tarefas específicas da aplicação consumindo e fornecendo recursos entre si.
Objetivo
Este padrão tem por objetivo decompor a aplicação em módulos reutilizáveis, organizados por 
funcionalidades específicas, como por exemplo, acesso a dados, lógica de negócio, construção 
da interface etc.
Contexto
O padrão de arquitetura em camadas é mais utilizado em sistemas grandes e complexos que 
necessitam de decomposição, pois frequentemente são compostos por operações de baixo e 
Pág. 28 de 91
alto nível. Deste modo, o agrupamento de tarefas comuns aumenta a escalabilidade e facilita a 
manutenção de camadas distintas.
Estrutura
Cada camada pode ser definida pela sua função e pelos vínculos que ela mantém com as outras 
camadas da aplicação. A estrutura desta arquitetura pode ser dividida em N-camadas, de acordo 
com a necessidade da aplicação. No entanto, o padrão mais utilizado é o de três camadas: interface 
com o usuário, lógica de negócio e acesso a dados. A figura a seguir ilustra este modelo.
Figura 20 – Modelo de arquitetura em três camadas
Fonte: Elaborado pelo autor.
Aplicabilidade
O padrão de arquitetura em camadas deve ser utilizado quando:
• tarefas similares podem ser agrupadas para facilitar a manutenção;
• a manutenção de um componente não afeta os outros;
• as partes do sistema podem ser substituídas de modo independente;
• há a possibilidade de utilizar recursos do sistema atual em projetos futuros;
• componentes complexos precisam ser decompostos;
• o limite entre os componentes é bem definido.
• Consequências
Vantagens:
• Boa reusabilidade devido ao encapsulamento.
• Suporte à padronização com a criação de frameworks.
• As dependências são restritas à camada.
Pág. 29 de 91
• Recursos intercambiáveis entre aplicações distintas.
Desvantagens:
• Queda de desempenho proporcional ao número de camadas.
• Alterações de comportamento podem provocar efeito cascata e causar gargalos.
Exemplo de aplicação
Considere o seguinte cenário: uma empresa possui diversas bases de dados alimentadas de 
modo independente e deseja fornecer informações processadas por uma única regra de negócio 
para diferentes plataformas de acesso.
Neste caso, a arquitetura em três camadas pode ser implementada permitindo o desenvolvimento 
de componentes específicos para bases distintas, interfaces adequadas para cada dispositivo e 
uma regra de negócios centralizada e compartilhada, conforme ilustrado na figura a seguir.
Figura 21 – Arquitetura em camadas para o exemplo de múltiplas bases e múltiplas plataformas
Camada de 
apresentação
Camada de Lógica de 
Negócio
Camada de Acesso 
a Dados
Fonte: Elaborado pelo autor.
Pág. 30 de 91
Padrão de arquitetura Pipes and filters ou Pipeline
De acordo com Buschmann et al. (2001), o padrão arquitetural Pipes and filters, também 
denominado Pipeline, permite um processamento sequencial por meio de etapas encapsuladas em 
componentes chamados filters que, por sua vez, são acoplados por meio de conexões conhecidas 
como pipes. A figura 22 ilustra este padrão.
Figura 22 – Arquitetura pipes and fi lters
Pipes (Conexões)
Data SinkData Source
Filters (Componentes)
Fonte: Elaborado pelo autor.
Objetivo
O padrão tem por objetivo decompor o sistema em etapas independentes, com o propósito de 
reutilizar esses módulos separadamente e facilitar a manutenção.
Contexto
Sistemas que processam sequências de dados e executam a mesma operação várias vezes 
podem fazer uso deste padrão para encapsular tarefas e reutilizá-las como etapas independentes, 
seja na mesma pipeline ou em outras.
Estrutura
De acordo com Buschmann et al. (2001), e conforme ilustrado na figura 22, a estrutura deste 
padrão é composta da seguinte forma:
Pág. 31 de 91
• Filters: são componentes responsáveis por transformar dados de entrada. O processamento de 
um filter deve depender apenas desses dados,a fim de permitir sua utilização no desenvolvimento 
de outros sistemas.
• Pipes: são as conexões entre filters, e são responsáveis pela transferência de dados e pela 
sincronização entre os componentes acoplados.
• Data Source: fonte de dados sequenciais padronizados.
• Data Sink: processo responsável por coletar o resultado final da sequência de processamento 
realizada pelos filters.
Aplicabilidade
O padrão pipes and filters pode ser aplicado nas seguintes condições:
• Dados de entrada e saída padronizados.
• Necessidade de processar dados sequenciais.
• Etapas paralelas não devem compartilhar informação.
• Deve ser viável realizar atualizações por meio de substituição parcial ou recombinação de filters.
Consequências
Vantagens:
• Reutilização de filters em aplicações distintas.
• Flexibilidade por meio da troca e recombinação de filters.
• Possibilidade de processamento paralelo.
• Desvantagens:
• Compartilhamento de estado intricado.
• Complexidade no tratamento de erros em cascata.
• Perda de desempenho no processamento dos dados em sequências com muitas etapas.
• Exemplo de aplicação
Considere o seguinte cenário: um banco realiza diversas transações financeiras ao processar 
arquivos de texto padronizados. Cada transação possui uma configuração específica para os dados 
de entrada. No entanto, várias operações são comuns em transações distintas.
Pág. 32 de 91
Figura 23 – Transações bancárias
Fonte: vasabii/Shutterstock
Neste exemplo, toda a entrada de dados será realizada via arquivos de texto, portanto, podemos 
utilizar um único componente para a leitura de arquivos. Contudo, as regras de negócio para cada 
transação são independentes, e devem ser empregados componentes específicos conforme a 
necessidade. Em uma etapa seguinte, todas as transações geram relatórios via outro componente 
compartilhado. Por fim, o componente Ler Arquivos é utilizado novamente para processar o conteúdo 
dos relatórios e disponibilizá-lo ao Data Sink. A figura 24 ilustra este exemplo.
Figura 24 – Arquitetura Pipes and Filters para transação fi nanceira 
com múltiplas entradas e processos compartilhados
Gerar Relatório
Processar
Transação A
Processar
Transação B
Reuso de componentes
Ler Arquivos
Transação B
Transação A
Data Source
Ler Arquivos Data Sink
1
1 1
1 1
1
1 1
11
1 1
1
0
0
0
0
0
0
0 0 0
00
0 0
1
1 1
1 1
1
1 1
11
1 1
1
0
0
0
0
0
0
0 0 0
00
0 0
Fonte: Elaborado pelo autor.
Pág. 33 de 91
2.4. Padrão de arquitetura Blackboard
O padrão Blackboard é utilizado para tratar problemas não determinísticos, como por exemplo, 
sistemas de inteligência artificial e reconhecimento de padrões. Neste padrão arquitetural, de acordo 
com Buschmann et al. (2001), diversos subsistemas unem seus conhecimentos para gerar uma 
possível solução parcial ou aproximada.
Objetivo
O objetivo do padrão arquitetural Blackboard é dividir um problema não determinístico entre 
subsistemas especializados para solucionar o objetivo de modo cooperativo.
Contexto
Este padrão pode ser aplicado em domínios imaturos ou complexos, compostos por diversos 
fatores sem solução algorítmica conhecida ou viável.
Estrutura
Este padrão é composto pelos seguintes itens:
• Blackboard: central de armazenamento de dados; as possíveis soluções e os dados de controle 
são armazenados aqui.
• Fontes de conhecimento: subsistemas independentes que resolvem aspectos específicos do 
problema. Nenhum deles pode resolver a tarefa do sistema sozinho; uma solução global só 
pode ser construída por meio da integração dos resultados de várias fontes de conhecimento.
• Central de controle: monitora as alterações no Blackboard, coordena as funções das fontes 
de conhecimento e decide a tomada de ações de acordo com a estratégia da aplicação. A 
estratégia é definida de acordo com as informações obtidas sobre o domínio.
Aplicabilidade
O padrão Blackboard pode ser aplicado nas seguintes condições:
• O problema possui dados incertos e admite soluções aproximadas.
• A pesquisa completa do espaço de soluções possíveis não é viável em um tempo razoável.
• O problema global pode ser resolvido através de soluções parciais, seguindo a abordagem 
“dividir para conquistar”.
• Os dados de entrada e saída, parcial ou global, têm representações distintas e os algoritmos 
devem ser implementados de acordo com paradigmas específicos.
Pág. 34 de 91
Figura 25 – “Dividir para conquistar”
Fonte: Yury Zap/Shutterstock
Consequências
Vantagens:
• Em domínios imaturos, há a possibilidade de experimentar diferentes algoritmos para mesma 
subtarefa, sem afetar as demais.
• Algoritmos disjuntos induzem a aplicação de paralelismo potencial, ou seja, as fontes de 
conhecimento podem ser exploradas em paralelo, porém, o acesso a central de dados deve 
ser sincronizado e compartilhado.
• Torna possível a experimentação com algoritmos distintos e também permite que diferentes 
heurísticas de controle sejam empregadas.
• Suporta mutabilidade e manutenção, porque as fontes de conhecimento, a central de controle 
e a estrutura de dados central são rigorosamente separadas.
• As fontes de conhecimento independentes são especializadas em tarefas específicas e podem 
ser reutilizadas em outras aplicações.
• Tolerância a falhas e conclusões duvidosas.
Desvantagens:
• Testes complexos, devido à dificuldade de reproduzir resultados não determinísticos.
• Não há garantia de uma solução ótima.
• Dificuldade para estabelecer uma boa estratégia de controle.
• Baixo desempenho computacional.
• Grande esforço no processo de desenvolvimento.
• Não suporta paralelismo integral.
Pág. 35 de 91
Exemplo de aplicação
Considere o seguinte cenário: uma aplicação de reconhecimento de voz (speech recognition) 
deve interpretar comandos, reconhecer o usuário e executar ações. Neste contexto, são empregados 
agentes distintos com as seguintes funções: interpretação de palavras isoladas, interpretação de 
comandos compostos como frases e reconhecimento de sinal de voz.
Figura 26 – Speech recognition
Fonte: Viktorus/Shutterstock
Este problema pode ser modelado da seguinte forma: um codificador repassa o sinal para um 
agente de reconhecimento, que por sua vez verifica as permissões de acesso para o usuário. Caso o 
acesso seja liberado, o sinal é encaminhado para o interpretador de palavras, que transforma o sinal 
em texto e envia o conjunto de palavras para a verificação de comandos compostos. Nesta etapa, 
um agente verifica se o padrão formado pelo conjunto de palavras extraídas do sinal é compatível 
com algum comando armazenado na estrutura de dados central. Esta sequência de controle pode 
ser induzida por meio de heurística ou inferida com o auxílio de algoritmos de aprendizado. A figura 
27 ilustra essa dinâmica.
Pág. 36 de 91
Figura 27 – Arquitetura Blackboard para reconhecimento de comandos de voz
Central de 
controle
Central de 
Dados
Fontes de Conhecimento
Controle de 
Usuário
Codi�cador
de Sinal
Interpretador 
de Palavras
Comando: “Liberar acesso.”
Sinal de Voz
Interpretador 
de Comandos
Fontes de Conhecimento
Aa
controle
Fonte: Elaborado pelo autor.
2.5. Model-View-Controller (MVC)
O padrão MVC é um modelo de camadas específico que divide a aplicação em três componentes:
• o Model, ou Modelo, que contém as funções básicas e o acesso aos dados;
• a View, ou visualizador, que exibe os dados para o usuário; e
• o Controller, ou controlador, que gerencia a interação entre as entradas do usuário e os dados 
do sistema.
Pág. 37 de 91
Figura 28 – MVC
Fonte: Bakhtiar Zein/Shutterstock
Objetivo
O objetivo do padrão MVC é garantir a coerência entre a interface do usuário e o modelo de 
dados da aplicação.
Contexto
As aplicações interativas com uma interface homem-computador flexíveis podem fazer uso 
deste padrão arquitetural.
Estrutura
Este padrão é composto da seguinte forma, de acordo com Buschmann et al. (2001):
• Model: encapsula o acessoaos dados e funções básicas da aplicação, fornecendo ao usuário 
procedimentos que executam tarefas específicas.
• View: exibe para o usuário os dados fornecidos pelo controle e estabelece uma interface para 
interação entre o usuário e a aplicação.
• Controller: interpreta eventos de entrada e envia requisições para o modelo de dados. Em 
seguida, processa os dados carregados a partir do modelo e envia para o visualizador.
Pág. 38 de 91
Aplicabilidade
O padrão MVC é muito flexível e pode ser aplicado em diversas situações. Como, por exemplo, 
nos casos em que:
• o projeto da interface deve ser desenvolvido separadamente;
• a mesma informação deve ser exibida em formas diferentes;
• a interface e o comportamento da aplicação devem refletir os dados do modelo em tempo real;
• alterações de interface devem ser simples e permitir mudanças em tempo real;
• há a necessidade de implementar um mecanismo de propagação de mudança para manter a 
coerência entre o modelo e a interface;
• é necessário suportar diferentes plataformas sem a necessidade de alterar a base da aplicação.
Consequências
Vantagens:
• Múltiplas interfaces para o mesmo modelo.
• Mecanismo de propagação de alteração entre o modelo e a interface.
• Interfaces e controladores intercambiáveis em tempo real.
• Criação de um possível framework.
Desvantagens:
• Aumento de complexidade.
• Propagação de atualizações excessiva.
• Alta dependência entre interface e controlador:
◊	 Interfaces e controladores podem ser altamente dependentes do modelo.
◊	 Interfaces e controladores podem ser altamente dependentes da plataforma.
• Ineficiência de acesso a dados por meio de interfaces com múltiplas requisições.
Exemplo de aplicação
Figura 29 – Multiplataformas
Fonte: ymgerman/Shutterstock
Pág. 39 de 91
Considere um sistema de gerenciamento que atende todos os departamentos de uma determinada 
empresa, da produção até a presidência. Vários funcionários fornecem e consomem informações 
simultaneamente via plataformas e dispositivos distintos, como computadores, celulares e tablets. 
Porém, para cada setor, as informações devem ser visualizadas da forma mais conveniente. Ou 
seja, os operadores têm acesso a informações específicas do seu trabalho, os gestores controlam 
planilhas detalhadas da sua equipe e a diretoria visualiza apenas os balancetes. A figura 30 ilustra 
esta situação.
Figura 30 – Arquitetura MVC aplicada à modelagem de um sistema de 
gerenciamento com base compartilhada e visualização personalizada
Diretoria
Gerência
Produção
View Controller Model
Fonte: Elaborado pelo autor.
SAIBA MAIS
Almeida (2017) traz um exemplo de aplicação em Java sem e com o uso do modelo MVC. Vale a pena 
verificar, implementar e testar.
Disponível no link: http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/arqu/mvc/mvc.htm >.
Pág. 40 de 91
Padrão de arquitetura Microkernel
O padrão arquitetural Microkernel se aplica a sistemas de software que devem ser capazes de 
se adaptar às necessidades de mudança do sistema. Ele separa um núcleo funcional mínimo de 
recursos estendidos e partes específicas. Este padrão também serve como um gerenciador para 
conectar essas extensões e coordenar a sua colaboração (BUSCHMANN et al., 2001).
Objetivo
O padrão Microkernel visa permitir o desenvolvimento de várias aplicações que utilizam interfaces 
de programação semelhantes e que compartilham as mesmas funcionalidades.
Contexto
Aplicações baseadas em módulos independentes podem utilizar o padrão Microkernel para 
gerenciar recursos adicionais.
Estrutura
A estrutura deste padrão é composta da seguinte forma:
• Microkernel: é o principal componente deste padrão. Ele implementa serviços centrais como 
comunicação e gerenciamento de recursos. Os módulos acoplados ao sistema podem utilizar 
as funcionalidades fornecidas pelo Microkernel.
• Servidores internos: componentes adicionais que estendem as funcionalidades do Microkernel. 
Servidores internos podem, portanto, encapsular algumas dependências no hardware subjacente 
ou sistema de software.
• Servidores externos: componentes que utilizam os recursos do Microkernel para executar 
suas próprias interfaces.
• Clientes: aplicativos associados a um servidor externo. Eles só acessam os recursos 
disponibilizados pelo servidor.
• Adaptadores: proporcionam uma interface entre clientes e servidores externos, permitindo 
que os clientes acessem os serviços fornecidos independentemente da plataforma.
Pág. 41 de 91
Figura 31 – Estrutura do padrão arquitetural Microkernel
Internal
Server A
Client A Client B Client C Client D
Internal
Server B
Microkernel
External Server A External Server B
Internal
Server C
Fonte: <http://suineg.info/microkernel-pattern/>.
Aplicabilidade
O padrão Microkernel pode ser aplicado nos seguintes casos:
• A aplicação deve suportar módulos diferentes em uma única plataforma.
• Os módulos podem ser categorizados em grupos que usam o mesmo núcleo funcional de 
diferentes maneiras.
• A plataforma de aplicações deve lidar com o hardware e contínua evolução do software.
• A plataforma de aplicação deve ser portável, extensível e adaptável para permitir uma fácil 
integração de tecnologias emergentes.
• O núcleo funcional da aplicação deve ser separado em um componente com tamanho mínimo, 
e os módulos devem ser adicionados conforme a necessidade.
Consequências
Vantagens:
• Portabilidade: na maioria dos casos, apenas o Microkernel precisa ser reescrito, e alterações 
de hardware demandam modificações apenas em suas dependências específicas.
• Flexibilidade e extensão: uma das maiores vantagens desta arquitetura é a capacidade de 
extensão e adaptação do sistema por meio da inclusão de novos módulos sem a necessidade 
de alterações no núcleo.
Pág. 42 de 91
• Separação de mecanismos e políticas: o Microkernel controla apenas os mecanismos básicos 
e permite que os módulos implementem suas políticas específicas.
• Escalabilidade: altamente adaptável em sistemas distribuídos.
• Confiabilidade: a tolerância a erros pode ser facilmente suportada porque os sistemas distribuídos 
permitem que se ocultem as falhas de um usuário.
• Transparência: em sistemas distribuídos, a arquitetura Microkernel permite que cada componente 
acesse outros serviços sem a necessidade de saber a sua localização.
Desvantagens:
• Desempenho: softwares monolíticos com foco específico são mais eficientes que a arquitetura 
Microkernel.
• Complexidade de concepção e implementação: a separação entre mecanismos e políticas 
requer um profundo conhecimento de domínio e um esforço considerável durante a análise 
de requisitos. Além disso, exige uma especificação meticulosa dos recursos disponibilizados 
pelo Microkernel.
Exemplo de aplicação
Suponha que você pretende desenvolver um novo sistema operacional para celulares que deverá 
atender aos seguintes requisitos: fácil portabilidade para qualquer aparelho, integração simplificada 
de novas aplicações e possibilidade de executar aplicativos de outros sistemas similares.
Figura 32 – Arquitetura Microkernel aplicada ao projeto de um sistema operacional (SO)
Aplicativos
Microkernel - Drivers e Funções Básicas do SO 
Emuladores
Aplicativos
Emulados
Fonte: Elaborado pelo autor.
Pág. 43 de 91
Neste caso, você deverá implementar uma estrutura elementar mínima que permita a expansão 
dos recursos com a inclusão de módulos. A execução de aplicativos externos poderá ocorrer por 
meio de adaptadores ou emuladores, que tenham acesso aos recursos do núcleo principal do 
sistema operacional. A figura 32 ilustra a estrutura deste exemplo.
SAIBA MAIS
O padrão de arquitetura Microkernel (algumas vezes referenciado como padrão de arquitetura plug-
in) é um padrão ideal para implementar aplicações baseadas em produtos. Este tipo de aplicação se 
refere a pacotes que são disponibilizados para download em versões como um produto de terceiros. 
Entretanto, muitas empresas também desenvolveme criam releases de aplicações na forma de 
produtos de software, notas de releases e recursos adicionais na forma de plug-ins.
Leia mais em: <https://www.oreilly.com/ideas/software-architecture-patterns/page/4/microkernel-architecture>.
Fonte: Richards (2015).
2.7. Padrão de arquitetura Reflection
O padrão Reflection fornece um mecanismo para alterar a estrutura e o comportamento de 
sistemas de forma dinâmica. Neste padrão, a arquitetura é dividida em duas partes: um nível meta, 
que provê informações sobre as propriedades do sistema, e um nível base, que inclui a lógica da 
aplicação. Alterações realizadas em informações contidas no nível meta afetam o comportamento 
do nível base (BUSCHMANN et al., 2001).
Objetivo
O padrão Reflection busca a criação de sistemas que suportem a sua própria modificação sem 
a necessidade de alterar a estrutura lógica da aplicação.
Contexto
Sistemas que dependem de adaptações frequentes podem implementar este padrão arquitetural 
para facilitar o processo de modificação.
Estrutura
Este padrão é composto pelos seguintes itens:
• Nível base: implementa a lógica da aplicação. Seus componentes representam os serviços 
fornecidos pelo sistema, o modelo de dados e a interface de usuário. E também específica a 
comunicação entre estas estruturas.
Pág. 44 de 91
• Nível meta: é composto por um conjunto de objetos que encapsulam informações específicas 
sobre um único aspecto da estrutura, comportamento ou estado do nível de base.
Aplicabilidade
O padrão Reflection pode ser aplicado nos seguintes casos:
• Adaptações constantes.
• Possibilidade de alterações parametrizadas.
• Necessidade de minimizar os efeitos colaterais de alterações invasivas.
Consequências
Vantagens:
• Não há alterações explícitas no código-fonte.
• Alterações no sistema são simplificadas por parâmetros.
• Suporte para vários tipos de alterações parametrizadas.
Desvantagens:
• Modificações incorretas nos parâmetros do nível meta podem causar falhas.
• Aumento do número de componentes proporcional à quantidade de parâmetros utilizados no 
nível meta.
• Baixa eficiência causada pela interpretação dos parâmetros em tempo de execução.
• Nem todas as alterações são suportadas por parâmetros.
• Nem todas as linguagens de programação suportam esta arquitetura.
Exemplo de aplicação
Figura 33 – HTML
Fonte: Rawpixel.com/Shutterstock
Pág. 45 de 91
Considere uma aplicação que necessita ler páginas HTML de um site para armazenar informações 
contidas entre tags específicas. O layout desse site, assim como a estrutura das suas páginas, varia 
frequentemente, o que demanda alterações constantes na aplicação. Neste caso, é possível definir 
um nível meta capaz de parametrizar a extração de informações do site, permitindo que a aplicação 
seja adaptada sem alterações específicas no código-fonte. A figura 34 ilustra este exemplo para a 
arquitetura Reflection.
Figura 34 – Arquitetura Reflection aplicada ao projeto de um sistema para 
extração de informações em websites com estrutura volátil
Interface de 
Usuário
Lógica de 
Negócio
Website - Mutável
Nível Base
Modelo de 
Dados
Parâmentros 
da Interface
Parâmentros 
da Lógica
Parâmentros 
do Modelo
Nível Meta
Fonte: Elaborado pelo autor.
SAIBA MAIS
Caelum (2017) traz um exemplo em Java de utilização do Reflection. Acesse o link: <http://www.caelum.
com.br/apostila-java-testes-xml-design-patterns/reflection-e-annotations/>.
Para ver um exemplo asp.net em Peixoto (2017) mostra um exemplo no link: <http://www.linhadecodigo.
com.br/artigo/1518/entendendo-o-reflectionaspnet_csharp.aspx>.
Pág. 46 de 91
3. DESIGN PATTERNS – PADRÕES DE CRIAÇÃO
Neste capítulo, definiremos o que é um padrão de projeto, quais são os padrões adotados pela 
comunidade de desenvolvedores e como eles são classificados. Depois, definiremos o que são 
padrões de criação e apresentaremos os principais padrões de criação, bem como exemplos de uso.
3.1. Conceitos de padrões de projeto
Os primeiros registros de design patterns ou padrões de projeto foram publicados por Erich 
Gamma, Richard Helm, Ralph Johnson e John Vlissides, em 1994, no livro Design patterns: elements 
of reusable object-oriented software. Estes padrões ficaram conhecidos como padrões GoF – Gang 
of Four, em referência aos quatro autores.
Figura 35 – Autores conhecidos como Gang of Four – GoF
Fonte: <http://slideplayer.com/slide/7462984/24/images/4/Gang+of+Four+(GoF)+http:/
www.research.ibm.com/designpatterns/pubs/ddj-eip-award.htm..jpg>.
Além dos padrões GoF, há diversos outros padrões de projeto. Craig Larman, em 2004, no 
seu livro Applying UML and patterns, reuniu um conjunto de padrões sob o acrônimo GRASP – 
General Responsibility Assignment Software Patterns (Padrões de Software para Atribuição de 
Responsabilidade Geral), que funcionam como um guia no desenvolvimento orientado a objetos, 
apoiando a organização por responsabilidades. O GRASP reúne nove padrões relevantes para o 
desenvolvimento de sistemas OO dirigidos por responsabilidades. Os nove padrões que compõem o 
GRASP são: Creator (criador); Information Expert (especialista); Low Coupling (baixo acoplamento); 
Controller (controlador); High Cohesion (alta coesão); Polymorphism (polimorfismo); Pure Fabrication 
(pura invenção); Indirection (indireção); Protected Variations (variações protegidas).
Pág. 47 de 91
Os padrões de projeto descrevem os princípios fundamentais da atribuição de responsabilidades 
a objetos. Esses padrões exploram os princípios fundamentais de sistemas OO.
Embora a adoção de padrões não seja trivial para um programador iniciante, este conceito tem 
sido adotado pela comunidade de desenvolvedores e cada vez mais exigido por líderes nas fábricas 
de software.
Como visto anteriormente, um código-fonte de um programa pode degradar-se ao longo de sua 
vida. Por princípio, os padrões buscam isolar as partes do código que são estáveis daquelas que 
são/serão mais suscetíveis a mudanças. O resultado que se espera é ter aplicações nas quais seja 
mais fácil efetuar procedimentos de manutenção, cujo código seja mais facilmente compreendido 
pela equipe do projeto, aumentando assim seu tempo de vida e postergando o início da degradação.
Os patterns são uma coleção de padrões de projeto de software, que oferecem soluções para 
problemas conhecidos e recorrentes no desenvolvimento de software. Um pattern descreve uma 
solução comprovada para um problema recorrente, dando ênfase ao contexto em que o problema 
ocorre e mostrando as consequências e o impacto de sua solução.
Figura 36 – Design patterns
Fonte: <https://www.linkedin.com/pulse/software-design-patterns-web-application-rajveer-gangwar>.
Assim, os patterns são dispositivos que permitem que os programadores compartilhem 
conhecimento sobre o seu projeto.
Pág. 48 de 91
Como desenvolvedores, sabemos que, quando programamos, encontramos muitos problemas 
que ocorrem, ocorreram e irão ocorrer novamente. A pergunta que sempre fazemos é: “Como vamos 
solucionar este problema desta vez?”. Documentar um padrão é uma maneira de podermos reusar 
e possivelmente compartilhar uma informação que aprendemos em relação à melhor maneira de 
se resolver um determinado problema de software.
As vantagens de se utilizar design patterns são muitas e incluem as seguintes:
• Os padrões já foram provados e refletem a experiência, o conhecimento e as soluções dos 
desenvolvedores que tiveram sucesso usando-os em seus trabalhos.
• Os padrões são reutilizáveis e oferecem uma solução pronta que pode ser aplicada a diferentes 
problemas.
• Os padrões proveem um vocabulário comum que pode expressar muitas soluções, de forma 
sucinta e objetiva.
No entanto, é importante lembrar que os padrões, por si só, não garantem o sucesso do seu 
uso. A descrição do padrão indica quando ele pode ser aplicado, mas apenas a experiência pode 
determinar quando um padrão particular irá melhorar o projeto do sistema.
O principalobjetivo de um design pattern é criar uma abstração de um problema recorrente e 
apresentar uma solução viável, além de poder compartilhar este conhecimento para que outras 
pessoas se beneficiem dele. Assim, a documentação de um design pattern deve ser feita de uma 
forma muito bem definida. De uma maneira geral, a documentação de um padrão inclui a definição 
dos seguintes itens:
• Objetivos ou pré-requisitos que devem ser satisfeitos antes de se decidir aplicar um padrão.
• A motivação ou o contexto em que o padrão se aplica.
• Uma descrição da estrutura do programa em que o padrão será definido.
• Consequências do uso do padrão, positivas e negativas.
• Exemplos de uso e aplicação do padrão
A figura 37 apresenta o mapa de padrões de projetos proposto pela Gang of Four. Parte destes 
padrões será abordada aqui.
Pág. 49 de 91
Figura 37 – Mapa de padrões de projetos GoF
Proxy
adding
operations
changing skin
versus guts
sharing
composites
de�ning
grammar
adding
operations
composed
using
de�ning
traversals
avoiding
hysteresis
saving state
of iteration
creating
composites
adding
responsibilities
to objects
de�nig
algorithm’s
steps
con�gure
factory
dynamically
single
instance
single
instance
implement
using
complex
dependency
management
often uses
de�ning
the chain
enumerating
children
sharing
terminal
symbols
sharing
states
sharing
strategies
Composite
Visitor
Chain of Responsibility
Mediator
Interpreter
State
Strategy
Flyweight
Adapter
Memento
Bridge
Template Method
Observer
Factory Method
Façade
Abstract Factory
Prototype
Singleton
Decorator
Command
Builder
Iterator
Fonte: <https://i2.wp.com/www.dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/relacoes.gif>.
Pág. 50 de 91
O catálogo de padrões GoF contém 23 padrões e está, basicamente, dividido em três seções:
• Creational (Padrões de criação).
• Structural (Padrões estruturais).
• Behavioral (Padrões comportamentais).
Os padrões de projeto GoF são soluções para problemas recorrentes no desenvolvimento de 
sistemas de software orientado a objetos. O quadro 2 (veja a seguir) mostra a divisão destes padrões, 
no contexto da programação orientada a objetos.
Os padrões de criação se referem à instanciação de objetos. Os estruturais estão ligados com 
a composição de classes ou objetos, e os comportamentais procuram caracterizar formas de 
interação entre classes e objetos. Um padrão GoF também é classificado segundo o seu escopo 
em 2 outros grupos:
• Padrões com escopo de classe: definidos por relacionamentos de herança e em tempo de 
compilação.
• Padrões com escopo de objeto: encontrados no relacionamento entre os objetos definidos 
em tempo de execução.
Quadro 2 – Divisão dos padrões GoF
Propósito
1. Criação 2. Estrutura 3. Comportamento
Escopo Classe Factory Method Class Adapter Interpreter
Template Method
Objeto Abstract Factory
Builder
Prototype
Singleton
Object Adapter
Bridge
Composite
Decorator
Facade
Flyweight
Proxy
Chain of Responsibility
Command
Iterator
Mediator
Memento
Observer
State
Strategy
Visitor
Fonte: Brizeno (2016).
A seguir, trataremos dos padrões de criação e, nos itens seguintes, apresentaremos os padrões 
estruturais e os comportamentais.
Mas, antes de prosseguirmos, um pouco de humor...
Pág. 51 de 91
Figura 38 – Tirinha
Fonte: Schissato e Pereira (2012).
Pág. 52 de 91
CURIOSIDADE
Ainda para manter o bom humor, leia o trecho a seguir, sobre princípios comuns de design 
(SCHISSATO; PEREIRA, 2012, s/p):
Há diversos princípios comuns de design, que, assim como os design patterns, 
tornaram-se boas práticas através dos anos e ajudaram que softwares de fácil 
manutenção pudessem ser construídos. A seguir, um resumo dos princípios 
mais conhecidos:
Keep it simple, stupid (KISS) – Mantenha isso simples, estúpido
Um problema comum em programação de software é a necessidade de complicar 
demais a solução. O objetivo do princípio KISS é manter o código simples, mas 
não simplista, evitando assim complexidade desnecessária.
Don’t repeat yourself (DRY) – Não se repita
O princípio do DRY é evitar a repetição de qualquer parte do sistema, abstraindo 
as coisas que são comuns entre si e colocando-as em um lugar único. Esse 
princípio não se preocupa somente com o código, mas com qualquer lógica que 
está duplicada no sistema.
Tell, don’t ask – Fale, não pergunte
O principio Tell, don’t ask está estreitamente alinhado com o encapsulamento 
e a atribuição de responsabilidades para as suas classes corretas. O princípio 
afirma que você deve dizer aos objetos quais ações você quer que eles realizem, 
em vez de fazer perguntas sobre o estado do objeto e então tomar uma decisão 
por si próprio em cima da ação que você quer realizar. Isso ajuda a alinhar as 
responsabilidades e evitar o forte acoplamento entre as classes.
You ain’t gonna need it (YAGNI) – Você não vai precisar disso
O princípio YAGNI se refere à necessidade de adicionar somente as funcionalidades 
que são necessárias para a aplicação e deixar de lado qualquer tentação de 
adicionar outras funcionalidades que você acha que precisa.
3.2. Definição de padrões de criação
Padrões de criação auxiliam na concepção de sistemas independentes do modo como os objetos 
são gerados, compostos e representados. De acordo com Gamma et al. (1995), este tipo de padrão 
abstrai o processo de instanciação, alterando a classe instanciada por meio de herança.
Pág. 53 de 91
Figura 39 – Detalhe da cena da criação, pintura da capela Sistina
Fonte: Creative Lab/Shutterstock
Assim, os padrões de criação concentram-se na composição de objetos complexos e no 
encapsulamento do comportamento de criação. Dessa forma, pretende-se evitar a ocorrência de 
códigos embutidos definindo pequenos grupos de características fundamentais, capazes de compor 
estruturas mais complexas.
Os padrões de criação podem ser competitivos ou cooperativos. Algumas técnicas se 
complementam, enquanto outras executam funções similares de formas distintas. As cinco 
abordagens presentes no modelo GoF são apresentadas a seguir.
3.3. Padrão Abstract Factory
Objetivo
De acordo com Gamma et al. (1995), o objetivo do padrão Abstract Factory é fornecer uma 
interface para criar grupos de objetos relacionados aos dependentes sem especificar suas classes 
concretas.
Figura 40 – Factory (fábrica)
Fonte: brumhildich/Shutterstock
Pág. 54 de 91
Contexto
Produtos portáveis utilizam o conceito abstrato deste padrão para desvincular código fundamental 
da aplicação de recursos que são dependentes da plataforma.
Estrutura
Este padrão é composto pelos seguintes elementos:
• Abstract Factory: declara uma interface para operações que criam objetos abstratos.
• Concrete Factory: implementa operações específicas para criar objetos concretos.
• Abstract Product: declara uma interface para cada tipo de objeto.
• Concrete Product: implementa uma interface de Abstract Product para definir um objeto que 
pode ser criado por sua Concrete Factory correspondente.
• Client: utiliza as interfaces declaradas pelo Abstract Factory e Abstract Product, sem se 
preocupar com as implementações concretas.
Aplicabilidade
O padrão Abstract Factory pode ser empregado nos seguintes casos:
• Um sistema deve ser independente do modo como seus objetos são criados, compostos e 
representados.
• Um sistema deve ser configurado com vários grupos distintos de objetos.
• Alguns objetos relacionados foram projetados para serem utilizados em conjunto, e você 
precisa impor essa restrição.
• Você quer fornecer uma biblioteca de classes e pretende revelar apenas suas interfaces, não 
suas implementações.
Consequências
Vantagens:
• Isola as classes concretas e ajuda a controlar as classes de objetos que um aplicativo cria.
• Torna fácil a troca de implementações específicas, pois a classe Concrete Factory aparece 
apenas onde é instanciada na aplicação.
• Promove a consistência entre produtos, pois facilita a implementação de

Continue navegando