Análise e Projeto Orientados  
por Objetos  
Aula 03 Padrões de Projeto GRASP  
Edirlei Soares de Lima  
<edirlei@iprj.uerj.br>  
Padrões de Projeto de Software  
Problemas no desenvolvimento de software se  
repetem...  
Bons desenvolvedores aplicam boas soluções para resolve-  
los.  
Por que não reutilizar as boas soluções em outros  
projetos?  
Padrões de software!  
É fundamental ter um repertório de soluções, de  
Padrões de Projeto.  
Padrões de Projeto de Software  
O que são padrões de software?  
A descrição de um problema que ocorre com freqüência;  
A base de uma solução para este problema com um nome;  
Baseado na reutilização de ideias (não de código).  
Padrões e mais padrões...  
Padrões de análise, padrões de testes, padrões de negócio,  
padrões pedagógicos, padrões arquiteturais, padrões de  
projeto (Design Patterns)...  
Elementos Essenciais de um Padrão de Software  
Nome:  
Resume em uma ou duas palavras: o problema, as soluções e  
consequências do uso do padrão;  
Deve ser facilmente lembrado, reflete o conteúdo do padrão;  
Problema:  
Descreve quando aplicar o padrão. Explica o problema, seu contexto,  
sintomas e condições;  
Solução:  
Elementos que constituem o design, seus relacionamentos,  
responsabilidades e colaboradores.  
Consequências:  
Resultados e compromissos decorrentes da aplicação do padrão;  
Impactos sobre a flexibilidade, extensibilidade, portabilidade ou  
desempenho do sistema.  
Elementos Essenciais de um Padrão de Software  
Outros elementos importantes:  
Um exemplo de uso;  
A razão que justifica a solução escolhida;  
Padrões relacionados;  
Uso conhecido do padrão;  
Lista de outros nomes para o padrão;  
Amostra de código em uma linguagem de programação.  
Elementos Essenciais de um Padrão de Software  
Nome:  
Deve ser sugestivo/representativo do problema ou  
solução;  
Apenas pelo nome, sabe-se a “natureza” do padrão;  
Todo mundo conhece os padrões:  
Nomes padronizados em inglês;  
Independente da equipe, estabelece-se comunicação de alto nível;  
Que padrão deve ser utilizado para que se tenha apenas  
uma instância de uma classe?  
Singleton  
Elementos Essenciais de um Padrão de Software  
Nome:  
Permite projetar em um nível mais alto de abstração;  
Exemplos de conversa entre desenvolvedores:  
Cara, acho melhor usar o Template Method aqui!!!”;  
Não sei não... um Strategy funcionaria melhor!!!”;  
Maria, coloca um Observer aí que resolve!!!”;  
Simplifica a documentação;  
Elementos Essenciais de um Padrão de Software  
Nome:  
Simplifica a documentação evitando longas descrições:  
/
*
*
*
*
*
*
*
*
** Nesta classe utiliza-se um  
construtor privado, com um método  
estático que retorna a única instância  
desta classe, sincronizado para evitar  
que outra instância seja recuperada  
por outra linha de execução...  
@author Joao da Silva  
@version 1.0  
/
public class Calendar{  
...  
/
*
*
*
*
** Nesta classe implementa-se  
o padrão Singleton...  
@author Joao da Silva  
@version 1.0  
/
public class Calendar{  
Elementos Essenciais de um Padrão de Software  
Problema:  
Em que situações o padrão pode ser aplicado?  
Em que situações o padrão traz flexibilidade/elegância ao  
projeto?  
Quando não utilizá-lo?  
O seu problema é similar ao descrito no padrão??? Se sim, basta  
uma adaptação da solução!!!  
Geralmente o problema tem exemplos específicos de aplicação:  
Como definir uma instância única de uma classe???  
Como representar algoritmos como objetos???  
Elementos Essenciais de um Padrão de Software  
Solução:  
Descreve os elementos que compõem o projeto da solução, suas  
responsabilidades e colaborações:  
Modelo conceitual;  
Diagrama de classes;  
Diagramas de interação;  
Solução não descreve uma implementação concreta, apenas um  
modelo genérico para que possa ser reutilizado  
Dependendo do seu problema, deverá ser adaptado  
Padrão é um gabarito de solução:  
Se João fez dessa forma e funcionou... porque não funcionaria  
comigo???”  
Elementos Essenciais de um Padrão de Software  
Consequências:  
Resultados do uso do padrão;  
Vantagens e desvantagens;  
Visão crítica: “o que se perde?”;  
Análise de impactos sobre;  
Flexibilidade;  
Extensibilidade  
Reuso;  
Desempenho;  
Padrões GRASP  
GRASP: General Responsibility Assignment  
Software Patterns.  
Padrões de análise catalogados por Craig Larman.  
Fornecem uma abordagem sistemática para a atribuição de  
responsabilidades às classes do projeto:  
De conhecimento (knowing): sobre dados privativos e encapsulados;  
sobre objetos relacionados; sobre coisas que pode calcular ou derivar.  
De realização (doing): fazer alguma coisa em si mesmo; iniciar uma  
ação em outro objeto; controlar e coordenar atividades em outros  
objetos.  
Padrões GRASP  
Padrões básicos:  
Padrões avançados:  
Polymorphism  
Pure Fabrication  
Indirection  
Information Expert  
Creator  
High Cohesion  
Low Coupling  
Controller  
Protected Variations  
Exemplo de Sistema  
Para a ilustração dos padrões GRASP analisaremos o exemplo  
de um sistema de vendas e pagamentos.  
Padrões GRASP são utilizados quase sempre durante a etapa de  
análise.  
Sistema:  
Grava vendas e gera pagamentos  
Vendas  
Pagamentos  
GRASP: Information Expert  
Princípio fundamental para atribuir responsabilidade.  
Problema: Qual é o princípio geral para a atribuição  
de responsabilidades aos objetos?  
Solução: Atribua a responsabilidade ao especialista:  
a classe que tem as informações necessárias para  
assumir a responsabilidade.  
GRASP: Information Expert  
Quem deve ser responsável por conhecer o total da venda?  
Venda  
-
-
dataVenda: data  
1
contêm  
1
..*  
EspecificaçãoProduto  
ItemVenda  
*
1
-
descriçao: texto  
preço: real  
quantidade: inteiro  
descrito por  
-
GRASP: Information Expert  
Quem deve ser responsável por conhecer o total da venda?  
Venda  
dataVenda: data  
1
Adiciona-se o  
método total()  
-
-
contêm  
1
..*  
EspecificaçãoProduto  
ItemVenda  
*
1
-
-
descriçao: texto  
preço: real  
quantidade: inteiro  
descrito por  
GRASP: Information Expert  
Quem deve ser responsável por conhecer o total da venda?  
Especialista sobre a venda  
Para cada ItemVenda...  
Recupera a EspecificaçãoProduto  
Recupera preço e quantidade do  
produto  
Venda  
-
dataVenda: data  
Calcula subtotal  
Soma ao total  
+
total(): real  
1
Fim  
Retorna total  
contêm  
..*  
1
EspecificaçãoProduto  
ItemVenda  
*
1
-
-
descriçao: texto  
preço: real  
-
quantidade: inteiro  
descrito por  
GRASP: Information Expert  
Quem deve ser responsável por conhecer o total da venda?  
Especialista sobre a venda  
Para cada ItemVenda...  
Recupera a EspecificaçãoProduto  
Recupera preço e quantidade do  
produto  
Venda  
-
dataVenda: data  
Calcula subtotal  
Soma ao total  
+
total(): real  
1
Fim  
Retorna total  
contêm  
..*  
1
EspecificaçãoProduto  
ItemVenda  
*
1
-
-
descriçao: texto  
preço: real  
-
quantidade: inteiro  
descrito por  
Adiciona-se o  
método subtotal()  
Quem é o especialista sobre  
EspecificaçãoProduto?  
GRASP: Information Expert  
Quem deve ser responsável por conhecer o total da venda?  
Especialista sobre a venda  
Para cada ItemVenda...  
Executa subtotal()  
Soma ao total  
Fim  
Venda  
-
dataVenda: data  
Retorna total  
+
total():real  
1
EspecificaçãoProduto  
contêm  
..*  
1
-
-
descriçao: texto  
preço: real  
1
ItemVenda  
quantidade: inteiro  
subtotal(): real  
*
descrito por  
-
+
Recupera preço do produto  
Multiplica pela quantidade  
Retorna subtotal  
GRASP: Information Expert  
Benefícios:  
Encapsulamento é mantido;  
Fraco acoplamento (facilidade de manutenção);  
Alta coesão (objetos fazem tudo relacionado à sua própria  
informação).  
No fim, vários especialistas "parciais" podem colaborar;  
Com o Expert, vários objetos inanimados podem ter ações;  
GRASP: Creator  
Problema: Quem deve ser responsável por criar uma nova  
instância de uma classe?  
Solução: Atribua à classe B a responsabilidade de criar uma  
instância de A se pelo menos um desses for verdadeiro  
(quanto mais melhor):  
B contém ou agrega objetos de A;  
B registra instancias de A;  
B usa muitos objetos de A;  
B tem os dados necessários para a inicialização de A que serão  
passados ao construtor de A;  
GRASP: Creator  
Que classe deve ser responsável por criar instâncias de  
ItemVenda?  
Venda  
dataVenda: data  
total():real  
1
Venda agrega vários  
ItemVenda  
-
+
contêm  
1
..*  
ItemVenda  
quantidade: inteiro  
subtotal(): real  
EspecificaçãoProduto  
*
1
-
-
-
descriçao: texto  
preço: real  
descrito por  
+
GRASP: Creator  
Que classe deve ser responsável por criar instâncias de  
ItemVenda?  
Venda  
-
dataVenda: data  
+
+
total():real  
adicionarItemVenda(qtd):void  
Adiciona-se um método  
adicionarItemVenda  
1
contêm  
1
..*  
ItemVenda  
quantidade: inteiro  
subtotal(): real  
EspecificaçãoProduto  
*
1
-
-
-
descriçao: texto  
preço: real  
descrito por  
+
GRAPS: Low Coupling (Baixo Acoplamento)  
Acoplamento é uma medida de quanto um elemento está  
conectado a, ou depende de outros elementos.  
Uma classe com acoplamento forte depende de muitas outras classes.  
Por isto, acoplamento forte é indesejável.  
Problema: Como prover baixa dependência entre classes,  
reduzir o impacto de mudanças e obter alta reutilização?  
Solução: Atribua as responsabilidades de modo que o  
acoplamento entre classes permaneça baixo. Use este  
princípio para avaliar alternativas.  
GRAPS: Low Coupling (Baixo Acoplamento)  
Uma classe com acoplamento forte é:  
Mais difícil de compreender isoladamente;  
Mais difícil de reutilizar (seu uso depende da reutilização das outras  
classes da qual ela depende);  
Sensível a mudanças nas classes associadas.  
GRAPS: Low Coupling (Baixo Acoplamento)  
Suponha que temos de criar um objeto pagamento e associá-  
lo à venda. Que classe deve ser responsável por isso?  
Segundo o padrão Creator, o Terminal de Vendas e Pagamentos (TDVP)  
deveria criar Pagamento e repassá-lo a Venda.  
façaPagamento()  
1:criar()  
:
TDVP  
2
p:Pagamento  
:façaPagamento(p)  
:
Venda  
Problema: três classes acopladas!  
GRAPS: Low Coupling (Baixo Acoplamento)  
Então, em nome do baixo acoplamento, ignoramos o Creator!  
façaPagamento()  
1:façaPagamento()  
:
TDVP  
:Venda  
1
.1:criar()  
p:Pagamento  
Agora temos acoplamento entre duas classes apenas.  
GRAPS: Low Coupling (Baixo Acoplamento)  
Acoplamento de dados:  
Objeto a passa objeto x para objeto b;  
Objeto x e b estão acoplados;  
Uma mudança na interface de x pode acarretar mudanças  
em b;  
Acoplamento de controle:  
Passar flags de controle entre objetos de forma que um  
objeto controle as etapas de processamento de outro  
objeto;  
Ocorrência comum:  
Objeto a manda uma mensagem para objeto b;  
b usa um parâmetro da mensagem para decidir o que fazer;  
GRAPS: Low Coupling (Baixo Acoplamento)  
class Lampada {  
public final static int ON = 0;  
public void setLampada(int valor)  
{
if (valor == ON) {  
/
/ liga lampada  
else if (valor == 1) {  
/ desliga lampada  
else if (valor == 2) {  
/ pisca  
}
}
}
/
/
}
}
Lampada lampada = new Lampada();  
lampada.setLampada(Lampada.ON);  
GRAPS: Low Coupling (Baixo Acoplamento)  
Solução: decompor em operações primitivas  
class Lampada {  
public void on()  
{
// liga lampada  
}
public void off()  
{
// desliga lampada  
}
public void pisca()  
{
// pisca  
}
}
GRAPS: Low Coupling (Baixo Acoplamento)  
Acoplamento de dados globais:  
Dois ou mais objetos compartilham estruturas de dados  
globais;  
É um acoplamento muito ruim pois está escondido;  
Uma chamada de método pode mudar um valor global e o  
código não deixa isso aparente;  
Acoplamento de dados internos:  
Um objeto altera os dados locais de um outro objeto;  
Dados públicos, protegidos...  
GRASP: High Coesion (Coesão Alta)  
Problema: como manter a complexidade sob  
controle?  
Classes que fazem muitas tarefas não relacionadas são:  
Mais difíceis de entender;  
Mais dificeis de manter e de reusar;  
São mais vulneráveis à mudança.  
Solução: atribuir uma responsabilidade para que a  
coesão se mantenha alta.  
GRASP: High Coesion (Coesão Alta)  
A coesão é uma medida do quão fortemente  
relacionadas e focalizadas são as responsabilidades  
de uma classe.  
Exemplo: uma classe Cachorro é coesa se:  
Tem operações relacionadas ao Cachorro (morder, correr,  
comer, latir);  
E apenas ao Cão (não terá por exemplo listarCaes);  
Alta coesão promove design modular.  
GRASP: High Coesion (Coesão Alta)  
Que classe é responsável por criar um pagamento e associá-lo  
a uma venda?  
De acordo com o Creator, novamente o TDVP deveria criar Pagamento.  
façaPagamento()  
1:criar()  
:
TDVP  
2
p:Pagamento  
:façaPagamento(p)  
:
Venda  
Suponha que isto ocorra várias vezes (outras classes):  
TDVP acumula métodos não relacionados a ele;  
Baixa coesão.  
GRASP: High Coesion (Coesão Alta)  
Faz mais sentido que o pagamento seja parte de  
Venda.  
E não do TDVP, como aparecia na solução anterior;  
Logo, TDVP delega a responsabilidade a Venda,  
aumentando a coesão de TDVP;  
façaPagamento()  
1:façaPagamento()  
:
TDVP  
:Venda  
1
.1:criar()  
Mesma solução de low coupling!  
p:Pagamento  
GRASP: High Coesion (Coesão Alta)  
Em um bom projeto OO, cada classe não deve fazer  
muito trabalho.  
Como perceber que a coesão de uma classe está  
baixa?  
Quando alguns atributos começam a depender de outros.  
Quando há subgrupos de atributos correlacionados na  
classe.  
Consequências:  
Melhor claridade e facilidade de compreensão do projeto;  
Simplificação da manutenção;  
Frequentemente causa baixo acoplamento;  
GRASP: Controller  
Problema: quem deve ser o responsável por lidar  
com um evento de uma interface de entrada?  
Solução: atribuir responsabilidades para receber ou  
lidar com um evento do sistema para:  
Uma classe que representa todo o sistema ou subsistema  
façade controller);  
Uma classe que representa cenário de caso de uso  
controlador de caso de uso ou de sessão).  
(
(
GRASP: Controller  
Que classe deve ser responsável por receber eventos  
do sistema?  
GRASP: Controller  
Normalmente, o controlador não realiza o trabalho,  
mas delega para outras subpartes do sistema.  
Possiveis escolhas:  
registraItem(id, qtd)  
:
TDVP  
registraItem(id, qtd)  
:
HandleProcessaVendas  
GRASP: Controller  
Benefícios:  
Diminui a sensibilidade da camada de apresentação em  
relação à lógica de domínio;  
Oportunidade para controlar o estado do caso de uso;  
É necessário balancear a quantidade de controladores:  
O problema mais comum é ter poucos controladores  
(controladores sobrecarregados).  
GRASP: Polymorphism  
Problema: como tratar alternativas baseadas no  
tipo? Como criar componentes de software  
"
plugáveis"?  
Solução: quando alternativas ou comportamentos  
relacionados variam com o tipo (classe), atribua as  
responsabilidades aos tipos usando operações  
polimórficas.  
GRASP: Polymorphism  
No sistema de vendas existem vários tipos de taxas,  
cujo comportamento varia de acordo seu tipo.  
Através de polimorfismo, podemos criar vários adaptadores  
semelhantes (mesma interface), que recebem uma venda e  
se adaptam para diferentes calculos de taxas.  
GRASP: Pure Fabrication  
Problema: que objeto deve ter a responsabilidade  
quando você não quer violar "Alta Coesão" e "Baixo  
Acoplamento", mas as soluções oferecidas pelo  
"
Expert" não são apropriadas?  
Solução: atribua um conjuto coeso de  
responsabilidades a uma classe artificial que não  
representa um conceito no domínio da aplicação, uma  
classe fictícia que possibilite alta coesão, baixo  
acoplamento e o reuso.  
GRASP: Pure Fabrication  
Qual classe é responsavel por salvar uma venda no  
banco de dados?  
Apesar de Venda ser a candidata lógica para ser a Expert  
para salvar a si mesma em um banco de dados, isto levaria  
o projeto a ter baixo acoplamento, alta coesão e baixo  
reuso.  
Uma solução seria criar uma classe responsável somente  
por isto.  
PersistentStorage  
+
+
insert(Object)  
update(Object)  
GRASP: Indirection  
Problema: Onde colocar uma responsabilidade de  
modo a evitar o acoplamento direto entre duas ou  
mais classes? Como desacoplar objetos de modo a  
possibilitar o baixo acoplamento e manter alta a  
possibilidade de reuso?  
Solução: Atribua a responsabilidade a um objeto  
intermediário que faça a mediação entre  
componentes ou serviços de modo que eles não  
sejam diretamente acoplados.  
GRASP: Indirection  
Exemplo: Indireção através de um adaptador  
GRASP: Indirection  
Exemplo: Indireção em um Sistema Bancário  
Classe Intermediaria  
GRASP: Protected Variations  
Problema: Como projetar objetos, subsistema e sistemas para  
que as variações ou instabilidades nesses elementos não  
tenha um impacto indesejável nos outros elementos?  
Solução:  
Identificar pontos de variação ou instabilidade potenciais e atribuir  
responsabilidades para criar uma interface estável em volta desses  
pontos;  
Encapsulamento, interfaces, polimorfismo, indireção e padrões são  
motivados por este princípio;  
Evite enviar mensagens a objetos muito distantes.  
GRASP: Protected Variations  
Exemplo:  
Classe que resolve  
incompatibilidades  
GRASP: Exercício  
Análise e projete o jogo Space Invaders aplicando os padrões  
GRASP na modelagem do sistema.  
Exercícios  
Lista de Exercícios 03  
http://www.inf.puc-rio.br/~elima/poo/