Escolar Documentos
Profissional Documentos
Cultura Documentos
PADRÕES DE
PROJETO
O guia
Ilustrado
POO
ANTES DE QUALQUER COISA
CLIQUE AQUI
PARA RESPONDER
Não se preocupe se você não sabe muita coisa sobre Design Patterns. O objetivo
deste quiz é justamente medir seus conhecimentos antes que você faça a leitura
deste e-book.
No final do e-book existe outro quiz como este. Se você se dedicar de verdade a
leitura deste e-book o resultado do quiz final com certeza será melhor que o
resultado do quiz inicial.
padroesdeprojeto.com.br Página 2
Olá,
POO
Esse material é resultado da minha
experiência como desenvolvedor e também
de muito estudo e planejamento, para que
eu pudesse entregar a você, de forma
gratuita, um conteúdo extremamente
didático.
padroesdeprojeto.com.br Página 3
Porque ESTUDAR
Design Patterns?
Eu não destaquei a palavra ESTUDAR em vão!
Jogar videogame.
padroesdeprojeto.com.br Página 5
Porque ESTUDAR
Design Patterns?
Dominar os Design Patterns é um dos fatores que
separam DEVs Júnior dos Plenos/Sênior.POO
Ao DOMINAR os Design Patterns, com certeza você já terá um grande conhecimento sobre
programação orientada a objetos.
Você terá muita consciência e cuidado com o nível de acoplamento do seu código, se ele
será fácil de ler, manter ou expandir.
Você já saberá exatamente quando é mais adequado utilizar uma classe abstrada, uma
interface ou então quando optar pela composição ao invés da herança.
padroesdeprojeto.com.br Página 6
Porque ESTUDAR
Design Patterns?
Ao dominar os Design Patterns
você estará em outro nível. POO
Pra você não bastará resolver o problema, pra você, o problema deverá ser resolvido
com excelência.
Veja bem, eu não estou te dizendo que você nunca mais fará uma gambiarra ou outra.
Eu também sou desenvolvedor e sei que as vezes os prazos são curtos e não dá pra
fazer tudo de forma perfeita.
Porém, você fará o melhor que você pode nas condições que você tiver!
Você não deixará de fazer o melhor por falta de conhecimento, mas sim, por uma
decisão consciente totalmente sua. Você terá segurança suficiente sobre seu código a
ponto de saber que a qualquer momento você poderá voltar ali e fazer melhor.
padroesdeprojeto.com.br Página 7
Porque ESTUDAR
Design Patterns?
Ou seja,
Você precisa estudar Design Patterns para não "surtar" quando tiver que dar
manutenção em um código que você mesmo escreveu.
Você precisa estudar Design Patterns para que outros desenvolvedores não "surtem"
ao ter que dar manutenção em um código que você escreveu.
Eu te garanto, por experiência própria, que as Te darão muitas horas "livres" no futuro para
horas "ocupadas" que você gastará estudando que você possa fazer aquilo que mais gosta.
Design Pattterns.
padroesdeprojeto.com.br Página 8
Agradecimentos
POO
Graças a eles eu pude me dar ao luxo de reservar horas do meu trabalho
para criar esse e-book gratuito.
padroesdeprojeto.com.br Página 9
"The only way to go fast is to go well"
POO
padroesdeprojeto.com.br Página 10
Atenção!
Antes de avançar nesse e-book eu preciso que você saiba de algumas coisas.
POO
Esse material é para desenvolvedores que possuem alguma experiência com
programação orientada a objetos.
padroesdeprojeto.com.br Página 11
Nivelamento
Para entender melhor o conteúdo
deste e-book é precisoPOO
compreender
alguns conceitos básicos sobre
padrões de projeto, digrama de
classes e orientação a objetos
00 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Nivelamento Página 12
AULAS DE NIVELAMENTO EM VÍDEO
Rabiscando Rabiscando
PADRÕES DE PADRÕES DE
PROJETO APERT
E PROJETO
Y
O PLA
POO
01 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Visitor Página 14
UM PRESENTE Rabiscando
PADRÕES DE
PRA VOCÊ PROJETO
AULA COMPLETA EM VÍDEO
E
VISITOR APERT
Y
O PLA
BÔNUS
MANUAL DE USO
COMPLETO EM PDF
02 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Singleton Página 16
SINGLETON
Padrão Criacional
ATENÇÃO: O singleton é
Conexao considerado um anti-pattern.
Sua utilização requer muita
instancia: Conexao | null cautela.
1
Talvez você esteja se perguntando o motivo ClienteA Conexao
do Singleton estar nesse e-book, já que ele é
considerado um anti-pattern. Os motivos con: Conexao
instancia: Conexao | null 2
são muito simples:
03 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Strategy Página 19
STRATEGY
Padrão Comportamental
DEFINIÇÃO: O padrão de projeto Strategy define uma família de PROBLEMA: Deseja-se criar
algoritmos, encapsula cada um deles e os torna intercambiáveis. uma calculadora de inteiros
O Strategy permite que o algoritmo varie independentemente dos que possa ter as operações
clientes que o utilizam. facilmente expandidas.
+ - ?
membros da família de operações sabem
calcular números.
* /
Família de Operações
(Família de algoritmos)
É obrigatório que todo membro dessa família tenha o método
calcular(operandoA, operandoB)
1
Calculadora <<interface>> 3
Operacao Família de Operações
operandoA: int (Família de algoritmos)
calcular(operandoA, operandoB)
operandoB: int
operacao: Operacao
4 4 4 4
setOperacao(Operacao operacao)
Soma Subtracao Multiplicacao Divisao
calcular(operandoA, operandoB)
/
2 return operandoA + OperandoB; return operandoA - OperandoB * return operandoA / OperandoB
2
1
O método setOperacao 3 Operacao é a interface ou classe que define o
A Calculadora é o cliente que utiliza o padrão É um Setter, ele é o responsável por dizer comportamento de cada estratégia (strategy). Em outras
de projeto Strategy. à Calculadora qual Operacao utilizar. palavras, para fazer parte da família de Operações têm
que segui as regras definidas em Operacao.
O método calcularOperacao
Os métodos cinza
O método calcular
É o responsável por invocar o método
São métodos exclusivos da Calculadora, eles calcular do objeto atribuído ao atributo
É o que dita o comportamento que deve ser
não fazem parte do padrão Strategy. Eles operacao por meio do método Setter.
implementado por todas as estratégias concretas. No
representam as demais funcionalidades que Exemplo nosso caso, calcular operações.
sua classe pode ter, ai no seu dia a dia de s = new Soma();
trabalho.
this->operacao = s
POO
04 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Factory Method Página 22
FACTORY METHOD
Padrão Comportamental
DEFINIÇÃO: O Padrão Factory Method define uma interface para PROBLEMA: Criar um
criar um objeto, mas permite que a subclasses possam decidir objeto manequim com uma
qual classe instanciar, possibilitando que uma classe seja capaz de peça de roupa.
prorrogar a instanciação de uma classe para subclasses.
Qual é o problema aqui? Imagine que ao invés de uma classe, existam 5 classes que precisem de um objeto
Roupa. Esse switch case iria se repetir em todas as classes. As regras para criar um objeto Roupa estariam
espalhadas por todo o sistema.
<<inteface>>
Cliente Manequim Roupa
Dependência
roupa: Roupa
Herança Herança
ManequimFormal ManequimCasual
Calcas Bermuda
Sapatos Tenis
switch (parteDoCorpo) { switch (parteDoCorpo) {
Conforme diz a
case 'tronco': case 'tronco':
definição, as
return new Camisa(); return new Camiseta();
subclasses decidem
case 'pernas': quais classes são case 'pernas':
return new Calcas(); instanciadas. return new Bermuda();
case 'pes': case 'pes':
return new Sapatos(); return new Tenis();
A classe Manequim foi subclassificada em
} }
ManequimFormal e ManequimCasual. Tais subclasses
implementam de forma concreta o método criarRoupa,
Detalhes interessantes: Aqui as Fabricas são os métodos das subclasses e não as subclasses. O
que por sua vez é o Factory Method.
padrão Factory Method utiliza Herança como recurso para diferenciar as maneiras que os
objetos são criados.
Camisa Camiseta
criarRoupa(string parteDoCorpo): Roupa Factory Method
Herança Herança
Sapatos Tenis
Exemplo de uma
classe Cliente
utilizando as Utilizando a subclasse
manequim = new ManequimFormal(); manequim = new ManequimCasual();
subclasses de ManequimCasual
Manequim. roupa = manequim.criarRoupa('tronco'); roupa = manequim.criarRoupa('tronco');
/*supondo que Manequim possui um método setter*/ /*supondo que Manequim possui um método setter*/
manequim.setRoupa(roupa); manequim.setRoupa(roupa);
Utilizando a
Subclasses diferentes
subclasse
resultam em objetos
ManequimFormal roupa = manequim.criarRoupa('pernas'); roupa = manequim.criarRoupa('pernas');
manequim.setRoupa(roupa); diferentes.
manequim.setRoupa(roupa);
1 <<inteface>> 3
Manequim Roupa
Dependência Abstrata
roupa: Roupa
Herança Herança
2 2
ManequimFormal ManequimCasual
Dependência Concreta
4 Sapatos 4 Tenis
2
As subclasses de Manequim ditam como e
qual objeto será criado pela implementação
concreta do Factory Method (criarRoupa).
POO
05 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Abstract Factory Página 28
ABTRACT FACTORY
Padrão Comportamental
Enquanto o padrão Factory Method fornece uma interface para a criação de objetos, o padrão Abstract As peças de roupas devem ser
Factory fornece uma interface para criar uma família de objetos.
coerentes com a ocasião. São
Em outras palavras, o Abstract Factory fornece uma interface para a criação de objetos que
elas: formal e casual. Além
fazem sentido juntos. Além disso, membros de uma família de objetos não devem se misturar disso o sistema deve ficar
com membros de outras famílias. aberto a novas ocasiões.
<<inteface>>
Roupa
Considere as mesmas classes de roupas que
utilizamos no padrão Factory Method.
Camisa Camiseta
ATENÇÃO: Para entender o
Aqui temos duas famílias de objetos: Abstract Factory recomendo
Traje Formal
que já tenha entendido o
Traje Casuais
padrão Factory Method.
Calcas Bermuda
Peças de roupas formais não devem Peças de roupas casuais não devem
se misturar com peças de roupas casuais. Sapatos Tenis se misturar com peças de roupas formais.
A classe Manequim espera apenas objetos do A classe Manequim espera 3 tipos diferentes de
Manequim tipo Roupa. Não existe distinção do tipo de Manequim objetos, uma para cada parte do corpo.
roupa que cada parte do manequim recebe.
tronco: Roupa tronco: RoupaTronco As Factories deve criar 3 objetos, um de cada
pernas: Roupa As Factories devem montar um manequim que pernas: RoupaPernas tipo.
pes: Roupa faça sentido, mas não existe controle explicito pes: RoupaPes
de tipos. Existe apenas uma convenção que Em nosso contexto uma famíla é composta por
cada factory sabe como criar determinados 1 objeto do tipo RoupaTronco, 1 do tipo
objetos, no nosso caso, Manequim. RoupaPernas e outro do tipo RoupaPes.
Camisa Camiseta
Objetos de tipos diferentes
Calcas Bermuda
Sapatos Tenis
TrajeFactory
Camisa Camiseta
criarRoupaTronco(): RoupaTronco
criarRoupaPernas(): RoupaPernas
criarRoupaPes(): RoupaPes
<<interface>>
RoupaPernas
TrajeFactoryFormal TrajeFactoryCasual
<<interface>>
RoupaPes
TrajeFactoryFormal cria
uma família que contém os
objetos das classes Camisa,
TrajeFactoryCasual cria
Calcas e Sapatos.
uma família que contém Sapatos Tenis
construtor(TrajeFactory factory)
TrajeFactory
criarRoupaTronco(): RoupaTronco
Abstract Factory
Os métodos de criarRoupaPernas(): RoupaPernas Os métodos de
TrajeFactoryFormal TrajeFactoryCasual
criarRoupaPes(): RoupaPes
serão chamados no serão chamados no
contrutor da classe contrutor da classe
Manequim. Manequim.
Factories Concretas
TrajeFactoryFormal TrajeFactoryCasual
Se no futuro surgirem
criarRoupaTronco(): Camisa criarRoupaTronco(): Camiseta novos trajes, bastará
criar novas Factories
criarRoupaPernas(): Calcas criarRoupaPernas(): Bermuda contretas.
criarRoupaPes(): Sapatos criarRoupaPes(): Tenis
tronco: RoupaTronco
pernas: RoupaPernas
pes: RoupaPes
construtor(TrajeFactory factory)
<<interface>>
RoupaPernas
TrajeFactory
criarRoupaTronco(): RoupaTronco
criarRoupaPes(): RoupaPes
TrajeFactoryFormal TrajeFactoryCasual
<<interface>>
criarRoupaTronco(): Camisa criarRoupaTronco(): Camiseta RoupaPes
06 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Facade Página 35
FACADE
Padrão Estrutural
Cabeca
BracoEsquerdo
criar
Cliente2
criar
BracoDireito
ClienteN
Tronco
criar
O Cliente 2 ainda não precisa
de um robô. Porém, se ele vir criar montarRobo
a precisar, também terá que
conhecer todas as classes e Qualquer cliente que vier a
processos envolvido na precisar de um Robô terá que
montagem de um robô. PernaEsquerda PernaDireita conhecer todo esse processo.
criar criar
1
Cliente Cliente2
... ClienteN
A classe Facade externaliza todo o subsistema
robô de uma forma simplificada.
BracoDireito 3
Tudo o que é
criar Embora a classe Facade simplifique o acesso, as
Tronco refente a robô
classes do subsistema continuam acessíveis. O
fica aqui dentro.
criar Facade é uma alternativa simplificada.
3 É importante dizer que a classe Facade pode possuir quantos métodos forem
necessários. Cada método pode simplificar o acesso a algumas classes apenas, não
necessariamente a todas as classes do subsistemas.
07 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Template Method Página 38
TEMPLATE METHOD
Padrão Comportamental
salada
O algoritmo é: TemplateMethod
1º - Adicione o pão cortado ao meio
Esse é o método responsável por definir o
2º - Adicione o Acompanhamento
1º algoritmo que utiliza os métodos da classe
3º - Adicione o Queijo
Hambúrguer.
4º - Adicione o Hambúrguer 2º
5º - Adicione a Salada 3º Podemos dizer que ele é a receita do
TemplateMethod = Método Molde 4º hambúrguer.
Sobreescreve
Sobreescreve
08 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Adapter Página 41
ADAPTER
Padrão Estrutural
DEFINIÇÃO: Converter uma interface de uma classe (incompatível) PROBLEMA: Para ter uma
para outra interface que o cliente espera encontrar. O Adapter conexão mais rápida
busca permitir que classes com interfaces incompatíveis deseja-se ligar um cabo
trabalhem juntas. Ethernet em um notebook
que possui apenas portas
USB.
1 5 6
Essa é nossa interface ALVO. O Aqui acontece o processo de É comum existir cenários onde 1
CLIENTE espera receber uma ADAPTAÇÃO. Cada método do ADAPTER método do ADAPER é equivalente
interface que tenha 1 método chama seu equivalente na classe a N métodos da classe
laranja, 1 vermelho e outro verde. ADAPTADA, recupera o retorno e o ADAPTADA e vice-versa.
fornece ao CLIENTE seguindo as
restrições impostas pela interface ALVO.
2 O cliente consumidor do
Nossa interface alvo é
A classe que temos não possui os padrão de projeto é
equivalente ao notebook equivalente a porta USB
métodos esperados pelo cliente.
As cores não batem.
4 Alvo
1
Cliente
3
A classe ADAPTER implementa a
interface alvo, logo, ela deve ter os
métodos (cores) que a interface
Alvo define.
3 2
Adapter Adaptada
4
O CLIENTE aceita objetos de
qualquer classe que implemente a
interface alvo. Ele sabe que a
interface alvo garante os métodos
nas cores que ele precisa.
Esse é nosso adaptador A classe adaptada é
Os métodos estão sendo equivalente ao cabo Ethernet
representados por cores (Classe incompatível)
09 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br State Página 44
STATE
Padrão Estrutural
Senha não
Validada
Senha
Validada
Bloqueado Desbloqueado
Bloquear
Travar
Destravar
O padrão também sugere que cada transição se torne um Método dos objetos de estado.
Travado
Bloqueado Desbloqueado Travado
<<interface>>
Senha
State
Validada
senhaValidada()
Bloqueado Desbloqueado
senhaNaoValidada()
Bloquear
bloquear()
Travar travar()
Destravar
destravar()
Travado
Travado
Quando existe transição a partir de um determinado estado, o método da transição possui implementação.
Quando não exite transição a partir de um determinado estado, o método da transição lança um erro.
Por exemplo: A partir do estado Desbloqueado não existe nenhuma transição Senha Validada, logo, o método senhaValidada da classe
Desbloqueado lança um erro.
Objeto de
O objeto de contexto é o contexto
objeto que troca de estado. <<interface>>
Smartphone State Para que os objetos de
No nosso caso a instância
estado possam trocar o
da classe Smartphone. bloqueadoState: State
desbloqueadoState: State
senhaValidada() estado atual do
travado: State senhaNaoValidada() Smartphone (objeto de
estadoAtual: State contexto) eles precisam
bloquear()
conhecer o Smartphone.
this.estadoAtual.senhaValidada(); contrutor() travar() Portanto, os objetos de
senhaValidada() destravar()
estado devem receber o
objeto Smartphone em
this.estadoAtual.senhaNaoValidada(); senhaNaoValidada()
seu construtor.
bloquear()
this.estadoAtual.bloquear(); travar()
destravar()
O estado inicial do objeto Smartphone Todos os objetos de estado são inicializados recebendo o
fica definido como sendo Bloqueado. próprio objeto Smatphone como parâmetro.
senhaNaoValidada()
bloquear()
destravar()
10 Rabiscando
PADRÕES DE
PROJETO
padroesdeprojeto.com.br Observer Página 52
OBSERVER
Padrão Comportamental
Subject:
Precisa fornecer um canal para que os observers possam se cadastrar como observadores. Esse objeto não
E também um canal para que os Observers possam se descadastrar como observadores. deseja receber as
Deve ser capaz de notificar todos os observers quando sofrer uma atualização (nova noticia). novidades
Objetos Observadores
(Observers)
Graças ao padrão Observer, agora não existe mais LeitorTipo1
o problema de solicitações desnecessárias
senhaValidada()
e
o novidad
Objeto que gera o assunto de interesse tenh Objeto Leitor A
(Subject) agora eu
Hey,
Os objetos Leitores
o novidade
Hey, agora eu tenh (Observers) podem ser
Hey, agora eu
tenho novida
instâncias de classes
de Objeto Leitor B diferentes
Hey,
agor
a eu
Objeto Leitor A Objeto Jornalista tenh
o no LeitorTipo2
vidad
Objeto Leitor B e
Objeto Leitor C
Objeto Leitor C senhaValidada()
Objeto Leitor D
Sempre que uma nova
Lista de objetos notícia é lançada o
que pediram para Jornalista notifica Objeto Leitor D
serem notificados todos os leitores que se
inscreveram
Aqui, 1 objeto Jornalista depende de muitos objetos leitores. Esse objeto não
(Dependencia um-para-muitos) deseja receber as
novidades
3 senhaValidada() observer)
inscrever(Observer senhaValidada() noticia)
receberNoticia(string 1
senhaValidada() observer)
desinscrever(Observer 4
5 notificar()
LeitorTipo1 LeitorTipo2
Jornalista
2 jornalista: Jornalista | null
senhaValidada() 2 jornalista: Jornalista | null
senhaValidada()
listaObservers: array
senhaValidada() receberNoticia(string noticia) receberNoticia(string noticia)
inscrever(Observer observer)
senhaValidada() observer)
desinscrever(Observer
notificar()
/* senhaValidada() observer)
desinscrever(Observer
Remove o observer recebido por parâmetro do array (ou
outra estrutura de dados) listaObservers. notificar()
Aqui você pode remover manualmente ou utilizar um //Recebe a noticia e faz algo com ela (manipula ou armazena)
método remove() ou qualquer outro método fornecido pela
sua linguagem de programação favorita. Os padrões de projeto são //O Jornalista pode se passado no construtor do observador
proposta de desing de código. public function construtor (Jonalista jornalista) {
O importante é remover o objeto observer a "lista" de Raramente você seguira a this.jornalista = jornalista;
objetos a serem notificados. implementação pura do padrão.
this.jornalista.inscrever(this);
*/ }
É comum que existam diversas
variações e adequações do
código do padrão, porém, //Para um maior nível de abstração
para cada objeto observer contido na listaObservers () { mantendo a ideia central que o //Também, é possível esperar o super tipo Subject no construtor
/*Em algum lugar de seu código o objeto produz uma padrão dita. //Nesse caso, o tipo do atributo no diagrama deveria ser trocado para "Subject | null"
noticia (string) e a envia para todos os observadores public function construtor (Subject jornalista) {
que se inscreverem em sua lista.*/
Veja ao lado algumas formas
this.jornalista = jornalista;
diferentes de implementar o
chamar o método receberNoticia(noticia); this.jornalista.inscrever(this);
processo de atribuição de um
} objeto Jornalista ao atributo }
jornalista dos Leitores (1 e 2).
//Um pouco mais baixo nível //Talvez seja interessante ter um método para gerenciar a observação de um Subject
foreach (listaObserver as observer) { Também repare no processo de public function observar (Subject jornalista) {
observer.receberNoticia(noticia); inscrição dos Leitores this.jornalista = jornalista;
} (observers) em um objeto this.jornalista.inscrever(this);
Jornalista. }
Quando entrei na universidade, meu objetivo inicial era ser professor universitário. Ao
POO
conversar com alguns professores, que se tornaram meus amigos, notei que a vida
acadêmica não era exatamente o que eu queria.
Te incentivo a fazer o mesmo, quanto mais conhecimento, melhor. Indique esse e-book
para as pessoas que acha que farão bom uso dele, assim como você.
Caso tenha alguma dúvida, sugestão, critica ou elogio sinta-se a vontate para escrever
para o e-mail abaixo. Darei o meu melhor pra te responder.
vinicius@padroesdeprojeto.com.br
padroesdeprojeto.com.br Página 57
Conheça o treinamento completo
Caso queira aprofundar ainda mais os seus conhecimento sobre os Padrões de Projeto
(Design Patterns). Eu te convido a conhecer o treinamento Rabiscando Padrões de
Projeto.
Rabiscando
POO
PADRÕES DE
PROJETO
Lá eu faço uma "Dissecação" completa de todos os 23 Design Patterns que foram
catalogados pela Gang of Four (GoF).
Você também terá a oportunidade de ver os padrões de projeto sendo aplicados para
resolver problemas reais, muito próximos ao que encontramos no nosso dia a dia como
desenvolvedores de software.
CONHEÇER
AGORA
padroesdeprojeto.com.br Página 58
Rabiscando
INTRODUÇÃO O PROJETO
Como REVISÃO DE O QUE SÃO PAdrões Conhecendo o
Abertura SUPORTE
ESTUDAR CONCEITOS de Projeto projeto pŕatico
ESTRUTURAIS Comportamentais
parte 1 parte 1
Template
FACADE DECORATOR ADAPTER STATE OBSERVER Strategy
Method
Comportamentais
DEMAIS PADRÕES parte 3
PROTOTYPE SINGLETON MEDIATOR MEMENTO VISITOR COMPOSITE PROXY
VOCê dominando os
AULA BÔNUS
ENCERRAMENTO padrões de projeto
INTERPRETER
(CRIANDO O PARSER)
Flyweight INTERPRETER Aula FINAL CERTIFICADO
padroesdeprojeto.com.br Página 59
O QUIZ FINAL
CLIQUE AQUI
PARA RESPONDER
Se você acertar pelo menos 7 das 10 questões já pode considerar que seus
estudos foram um grande sucesso!
padroesdeprojeto.com.br Página 60
AVALIAÇÃO DO E-BOOK
CLIQUE AQUI
PARA AVALIAR
padroesdeprojeto.com.br Página 61
Certa vez ouvi uma frase que me marcou. Infelizmente não
lembro o nome do autor para dar os créditos. Era algo assim:
Até a próxima!
padroesdeprojeto.com.br Página 62