Sie sind auf Seite 1von 122

Padrões de Projeto

Sistemas de Informação I

Melina Mongiovi

melina@computacao.ufcg.edu.br

Baseado nos slides do Prof. Tiago Massoni


Desenvolver software de
qualidade
Alguém, em algum lugar,
já resolveu o seu
problema de design
(ou quase o mesmo problema…)
public class ContaEstacionamento {

private Veiculo veiculo;


private long inicio, fim;

public double valorConta() {

long atual = (fim == 0) ? System.currentTimeMillis() : fim;


long periodo = inicio - atual;

if (veiculo instanceof Passeio) {


if (periodo < 12 * HORA) {
return 2.0 * Math.ceil(periodo / HORA);
} else if (periodo > 12 * HORA && periodo < 15 * DIA) {
return 26.0 * Math.ceil(periodo / DIA);
} else {
return 300.0 * Math.ceil(periodo / MES);
}
} else if (veiculo instanceof Carga) {
// outras regras para veiculos grandes
}
// outras regras para outros veiculos
return 0.0;
}
}
public class ContaEstacionamento {

private Veiculo veiculo;


private long inicio, fim;

public double valorConta() {

long atual = (fim == 0) ? System.currentTimeMillis() : fim;


long periodo = inicio - atual;

if (veiculo instanceof Passeio) {


if (periodo < 12 * HORA) {
return 2.0 * Math.ceil(periodo / HORA);
} else if (periodo > 12 * HORA && periodo < 15 * DIA) {
return 26.0 * Math.ceil(periodo / DIA);
} else {
return 300.0 * Math.ceil(periodo / MES);
}
} else if (veiculo instanceof Carga) {
// outras regras para veiculos grandes
}
// outras regras para outros veiculos
return 0.0;
}
}
public class ContaEstacionamento {

private Veiculo veiculo;


private long inicio, fim;

public double valorConta() {

long atual = (fim == 0) ? System.currentTimeMillis() : fim;


long periodo = inicio - atual;

if (veiculo instanceof Passeio) {


if (periodo < 12 * HORA) {
return 2.0 * Math.ceil(periodo / HORA);
} else if (periodo > 12 * HORA && periodo < 15 * DIA) {
return 26.0 * Math.ceil(periodo / DIA);
} else {
return 300.0 * Math.ceil(periodo / MES);
}
} else if (veiculo instanceof Carga) {
// outras regras para veiculos grandes
}
// outras regras para outros veiculos
return 0.0;
}
}
public class ContaEstacionamento {

private Veiculo veiculo;


private long inicio, fim;

public double valorConta() {

long atual = (fim == 0) ? System.currentTimeMillis() : fim;


long periodo = inicio - atual;

if (veiculo instanceof Passeio) {


if (periodo < 12 * HORA) {
return 2.0 * Math.ceil(periodo / HORA);
} else if (periodo > 12 * HORA && periodo < 15 * DIA) {
return 26.0 * Math.ceil(periodo / DIA);
} else {
return 300.0 * Math.ceil(periodo / MES);
}
} else if (veiculo instanceof Carga) {
// outras regras para veiculos grandes
}
// outras regras para outros veiculos
return 0.0;
}
}
public class ContaEstacionamento {

private Veiculo veiculo;


private long inicio, fim;

public double valorConta() {

long atual = (fim == 0) ? System.currentTimeMillis() : fim;


long periodo = inicio - atual;

if (veiculo instanceof Passeio) {


if (periodo < 12 * HORA) {
return 2.0 * Math.ceil(periodo / HORA);
} else if (periodo > 12 * HORA && periodo < 15 * DIA) {
return 26.0 * Math.ceil(periodo / DIA);
} else {
return 300.0 * Math.ceil(periodo / MES);
}
} else if (veiculo instanceof Carga) {
// outras regras para veiculos grandes
}
// outras regras para outros veiculos
return 0.0;
}
}
public class ContaEstacionamento {

private Veiculo veiculo;


private long inicio, fim;

public double valorConta() {

long atual = (fim == 0) ? System.currentTimeMillis() : fim;


long periodo = inicio - atual;

if (veiculo instanceof Passeio) {


if (periodo < 12 * HORA) {
return 2.0 * Math.ceil(periodo / HORA);
} else if (periodo > 12 * HORA && periodo < 15 * DIA) {
return 26.0 * Math.ceil(periodo / DIA);
} else {
return 300.0 * Math.ceil(periodo / MES);
}
} else if (veiculo instanceof Carga) {
// outras regras para veiculos grandes
}
// outras regras para outros veiculos
return 0.0;
}
}
public class ContaEstacionamento {

private Veiculo veiculo;


private long inicio, fim;

public double valorConta() {

long atual = (fim == 0) ? System.currentTimeMillis() : fim;


long periodo = inicio - atual;

if (veiculo instanceof Passeio) {


if (periodo < 12 * HORA) {
return 2.0 * Math.ceil(periodo / HORA);
} else if (periodo > 12 * HORA && periodo < 15 * DIA) {
return 26.0 * Math.ceil(periodo / DIA);
} else {
return 300.0 * Math.ceil(periodo / MES);
}
} else if (veiculo instanceof Carga) {
// outras regras para veiculos grandes
}
// outras regras para outros veiculos
return 0.0;
}
}
public class ContaEstacionamento {

private Veiculo veiculo;


Problema 1: como
private long inicio, fim; melhorar este design?
public double valorConta() {

long atual = (fim == 0) ? System.currentTimeMillis() : fim;


long periodo = inicio - atual;

if (veiculo instanceof Passeio) {


if (periodo < 12 * HORA) {
return 2.0 * Math.ceil(periodo / HORA);
} else if (periodo > 12 * HORA && periodo < 15 * DIA) {
return 26.0 * Math.ceil(periodo / DIA);
} else {
return 300.0 * Math.ceil(periodo / MES);
}
} else if (veiculo instanceof Carga) {
// outras regras para veiculos grandes
}
// outras regras para outros veiculos
return 0.0;
}
}
solução

Polimorfismo
Passeio Passeio Passeio
Problema:
- explosão de subclasses

- não é possível alterar o comportamento

Passeio Passeio Passeio


solução 2
Problema: duplicação
de código
O que precisamos…
- Diferentes algoritmos de cálculo de tarifa possam
ser usados pela mesma classe

- Reduzir duplicação de código

- O mesmo algoritmo possa ser usado por diferentes


empresas

- Uma classe deve poder iniciar a execução com um


algoritmo e este ser trocado posteriormente
recordando o princípio

separar aquilo que varia daquilo que


se mantém o mesmo
Veiculo

ComportamentoCalculo
Veiculo
supertipo

ComportamentoCalculo

CalculoHorario CalculoDiario

subtipos
public class Estacionamento2 {


private Veiculo veiculo;

private long inicio, fim;


public double valorConta() {

long atual = (fim == 0) ?
System.currentTimeMillis() : fim;

long periodo = inicio - atual;


return veiculo.calcular(periodo);

}

}
public class Estacionamento2 {


private Veiculo veiculo;

private long inicio, fim;


public double valorConta() {

long atual = (fim == 0) ?
System.currentTimeMillis() : fim;

long periodo = inicio - atual;


return veiculo.calcular(periodo);

}

}
public abstract class Veiculo {


private ComportamentoCalculo estrategia;


public double calcular(long periodo);

}

public class Passeio extends Veiculo {





public double calcular(long periodo) {


estrategia = Fabrica.criarEstrategia(periodo);

double valor = estrategia.calcular(periodo);


//... processa valor com regras para veiculo


return valor;

}

}
public abstract class Veiculo {


private ComportamentoCalculo estrategia;


public double calcular(long periodo);

}

public class Passeio extends Veiculo{





public double calcular(long periodo) {


estrategia = …;

double valor = estrategia.calcular(periodo);


//... processa valor com regras para veiculo


return valor;

}

}
public class CalculoDiaria
implements ComportamentoCalculo{

private static final long HORA = 60;

private double valorDiaria;


@Override

public double calcular(long periodo) {

return valorDiaria * Math.ceil(periodo / HORA);

}

}
public class CalculoDiaria
implements ComportamentoCalculo{

private static final long HORA = 60;

private double valorDiaria;


@Override

public double calcular(long periodo) {

return valorDiaria * Math.ceil(periodo / HORA);

}

}
Strategy é um DESIGN PATTERN
Problema
Classes diferem apenas pelo seu comportamento

Polimorfismo puro provoca duplicação de código

29
Como você descreveria a solução que
acabamos de ver, para um colega com um
problema parecido?

Problema: Ele está implementando uma aplicação que exporta um


documento para os formatos pdf e html. O usuário pode exportar o
documento para qualquer um desses formatos e a qualquer
momento.
Strategy
Encapsula algoritmos relacionados em classes que são
subclasses de uma classe comum
Permite a seleção de algoritmo variar por objeto e também em
tempo de execução

31
Consequências

- múltiplas variações de comportamento em tempo


de execução encapsuladas em uma classe separada
esconde detalhes de implementação de quem usa

- cria novas classes que não existiam antes


Nem tudo são flores…

- Aumento da complexidade na criação do objeto


- Caso o atributo seja nulo, a classe pode apresentar
comportamento inesperado
- Aumento do número de classes (uma para cada
algoritmo)
- Dificuldade de gerenciamento
O simples uso da orientação a objetos
não garante sistemas extensíveis e
reutilizáveis
Padrões (Patterns)
Ideia da arquitetura (1979)
Christopher Alexander
The Timeless Way of Building

contexto-problema-solução

melhorar o projeto de
edifícios e áreas urbanas

arcos e colunas são uma


estratégia comprovada para
construir edificações
seguras
projeto e instalação de portas
e janelas seguem um padrão
estabelecido
Gang of Four (GoF)

1994

2004
Padrões em software
Transferido para software em um livro
clássico: GoF (1994)
soluções recorrentes de classes e objetos
Padrões de projeto
Soluções para problemas de projeto OO
Previamente experimentados e testados
Resolvem problemas similares
ocorridos em vários contextos
enorme quantidade de publicações
O que é um Padrão de projeto?

Um padrão descreve um problema que ocorre


repetidas vezes em nosso ambiente, e então
descreve o núcleo da solução para aquele
problema, de tal maneira que você pode usar essa
solução milhões de vezes em situações diferentes

• Reuso de experiência e não de código


Benefícios

- Permitem compartilhar experiências bem sucedidas na


resolução de problemas
- Reduzem a complexidade do processo de projeto de
software
- Aumentam confiabilidade do software via o uso de
arquiteturas comprovadas e experiência acumulada
- Aumentam grau de reutilização de software
Vocabulário comum
Possível problemas
Aumenta número de objetos
desempenho
complexidade
Ansiedade por saber TODOS os padrões
Classificação: Propósito
• Criação
– Preocupam com o processo de criação de objetos
• Estrutural
– Lidam com a composição de classes ou objetos
• Comportamental
– Caracterizam as maneiras pelas quais classes ou
objetos irão interagir para realizar um dado
comportamento
Classificação: Escopo
• Classe
– Lidam com os relacionamentos entre classes e
suas subclasses.
– São estabelecidos através do mecanismo de
herança
• Objeto
– Lidam com relacionamentos entre objetos que
podem ser mudados em tempo de execução e são
mais dinâmicos
Padrões do GoF
O Formato de um padrão
Forma de descrever padrões deve ser o mais
uniforme possível
Todo padrão inclui
Nome
Problema
Solução
Conseqüências (prós,contras)
Existem vários tipos de formato, em vários livros
Não há padronização no formato
Voltando ao Strategy…
Nome: Strategy
Problema: Uma classe possui diversos algoritmos que
podem ser usados de forma intercambiável
Solução: Delegar a execução do algoritmo para uma
instância que compõe a classe principal
Consequências: + algoritmo pode ser alterado sem a
modificação da classe
+ redução da lógica condicional da classe principal
+ implementação pode ser trocada em tempo de
execução
- aumento do número de classes
- aumento da complexidade na criação do objeto
- dificuldade de gerenciamento
Quanto mais padrões eu utilizar,
melhor vai ficar meu código?
Problema: como garantir que só existe
uma lista de pedidos no sistema todo?

class ListaPedidos {
public ListaPedidos(Pedido [] p) {

}
}
Definir uma única instância de uma classe
na memória
todos os serviços requisitados ao mesmo
objeto

obj1 obj2 obj3 obj4

Instancia única de um objeto


Singleton
public class ListaPedido {
private static ListaPedido instancia;

private Gerenciador() {
... //construcao do objeto
}

public static Gerenciador obterInstancia() {


if (instancia == null) {
instancia = new Gerenciador();
}
return instancia;
}
Singleton
public class ListaPedido {
private static ListaPedido instancia;

private ListaPedido() {
... //construcao do objeto
}

public static Gerenciador obterInstancia() {


if (instancia == null) {
instancia = new Gerenciador();
}
return instancia;
}
Singleton
public class ListaPedido {
private static ListaPedido instancia;

private ListaPedido() {
... //construcao do objeto
}

public static ListaPedido obterInstancia() {


if (instancia == null) {
instancia = new Gerenciador();
}
return instancia;
}
Singleton
public class ListaPedido {
private static ListaPedido instancia;

private ListaPedido() {
... //construcao do objeto
}

public static ListaPedido obterInstancia() {


if (instancia == null) {
instancia = new ListaPedido();
}
return instancia;
}
Consequências

+ acesso controlado à instância única

- torna o código mais difícil de ser


testado (estado global é difícil de ser
isolado com teste de unidade)
- difícil de implementar em ambientes
distribuídos
Como garantir que uma classe
(Configuracao) que representa e
armazena configurações do sistema
possui uma única instância?
Problema: Imagine que em uma aplicação
precisamos pegar mapas de propriedades e
serializar em arquivos. Existem duas
possibilidades de gerar arquivos: XML
compactado ou de propriedades criptografado.
configurações

sistema=xyz

versao=0.0.1

plataforma=MS Windows

sgbd=MySQL

autor=Jean Jorge Michel
configurações
serialização

pós-
processamento
public void gerarArquivo(String nome,
Map<String,Object> propriedades)

throws IOException{


String conteudo = "";

if (opcaoGeracao == TXT)

conteudo = gerarConteudoTXT(propriedades);

else if (opcaoGeracao == XML)

conteudo = gerarConteudoXML(propriedades);


byte [] bytes = conteudo.getBytes();


if (opcaoGeracao == TXT)

//transforma bytes em

bytes = criptografar(bytes);

else if (opcaoGeracao == XML)

bytes = compactar(bytes);


FileOutputStream fileout = new FileOutputStream(nome);

fileout.write(bytes);

fileout.close();

}
public void gerarArquivo(String nome,
Map<String,Object> propriedades)

throws IOException{


String conteudo = "";

if (opcaoGeracao == TXT)

conteudo = gerarConteudoTXT(propriedades);

else if (opcaoGeracao == XML)

conteudo = gerarConteudoXML(propriedades);


byte [] bytes = conteudo.getBytes();


if (opcaoGeracao == TXT)

//transforma bytes em

bytes = criptografar(bytes);

else if (opcaoGeracao == XML)

bytes = compactar(bytes);


FileOutputStream fileout = new FileOutputStream(nome);

fileout.write(bytes);

fileout.close();

}
public abstract class Serializador {


public abstract String
gerarConteudo(Map<String,Object> propriedades);

public abstract byte [] processar(byte[] bytes);


public void gerarArquivo(String nome,
Map<String, Object> propriedades)

throws IOException{


String conteudo = gerarConteudo(propriedades);


byte [] bytes = conteudo.getBytes();


bytes = processar(bytes);


FileOutputStream fileout = new FileOutputStream(nome);

fileout.write(bytes);

fileout.close();

}

}
public abstract class Serializador {


public abstract String
gerarConteudo(Map<String,Object> propriedades);

public abstract byte [] processar(byte[] bytes);


public void gerarArquivo(String nome,
Map<String, Object> propriedades)

throws IOException{


String conteudo = gerarConteudo(propriedades);


byte [] bytes = conteudo.getBytes();


bytes = processar(bytes);


FileOutputStream fileout = new FileOutputStream(nome);

fileout.write(bytes);

fileout.close();

}

}
public class SerializadorXMLCompactado
extends Serializador {


@Override

public String
gerarConteudo(Map<String, Object> propriedades){

//codigo para transformar propriedades
//em arquivo xml

}


@Override

public byte[] processar(byte[] bytes) {

//codigo para transformar xml em
//conteudo compactado

}

}
public void gerarArquivo(…) {
String conteudo = gerarConteudo(props);
byte[] bytes = conteudo.getBytes();
bytes = processar(bytes);

}

GeradorArquivo

gerarArquivo(…)
abstract gerarConteudo (…)
hook methods
processar (…)

GeradorXMLCompactado GeradorTXTCriptografado

gerarConteudo (…) gerarConteudo (…)


processar (…) processar (…)
Método-gancho (hook method)
public void metodoPrincipal() {
//executa lógica comum
metodoGancho();
Superclasse //executa lógica comum
}

metodoPrincipal()
metodoGancho()

Importância do uso da
herança:
Subclasse A Subclasse B
permitir especialização
de comportamento
metodoGancho() metodoGancho()
Passos diferentes na mesma ordem:
Template Method
Template
Template Method

- Modelo de algoritmo com partes fixas e variáveis


- Partes variáveis: lacunas que precisam ser preenchidas
- Lacunas: hook methods implementados nas subclasses
- Lacuna obrigatória: método é abstrato
- Lacuna opcional: método é concreto com implementação vazia
Consequências

+ Evita duplicação de código nas subclasses


+ Reaproveitamento de código relativo à parte comum de
um algoritmo
+ Definir funcionalidade geral que pode ser incorporada a
parte específica do domínio da aplicação

- Herança é "uma carta que só pode ser jogada uma vez"


Como criar os
serializadores?
Exercício
*Em cada operação do sistema:

if (server == oracle)
consulta = new ConsultaOracle();
else
<<interface>> consulta = new ConsultaSQL();
ConsultaBD consulta.executar(…);

executar(…)

Pode haver necessidade de


ConsultaOracle ConsultaSQLServer funcionar em outros BDs

executar(…) executar(…)
Factory Method
Solução
interface com modo de instanciar decidido em tempo de
execução
onde este código Java usa
o padrão Factory Method?
ArrayList al = new ArrayList(); 
// use iterator to display contents of al
System.out.print("Original contents of al: ");
Iterator itr = al.iterator();
while(itr.hasNext()) {

Object element = itr.next();


System.out.print(element + " ");

}
Problema
<<interface>> E se tivermos que criar
ConsultaBD
UpdateBD,
executar(…)
DeleteBD,
InsertBD?

ConsultaOracle ConsultaSQLServer

executar(…) executar(…)
Criando uma família de
objetos
class Motor {
public abstract boolean testar();
}
class MotorRenault extends Motor{
public boolean testar(){
//testa motor renault 

}
}
class MotorToyota extends Motor{...}

class Chassi{
public abstract boolean testar();
}
class ChassiRenault extends Chassi{
public boolean testar(){
//testa chassi renault 

}
}
class ChassiToyota extends Chassi{...}
Problema

//aplicacao de montadora que usa motores


Motor m; Chassi c;
switch (opcao)
case `r’: m = new MotorRenault();
c = new ChassiRenault();
case ‘t’: m= new MotorToyota();...

ok = m.testar();
ok2 = c.testar();

78
Abstract Factory
Factory method!
Fábrica abstrata!
Exemplo da solução
//Montadora
Motor m;
FabricanteAutomoveis fa =
FabricanteAutomoveis.criarFabrica(“toyota”);

m = fa.criarMotor();
ok = m.testar();

79
Abstract Factory: solução

80
Abstract Factory
criação de famílias de objetos
Regras de instanciação guardadas nas fábricas concretas
Consequências

+ Diminui dependência entre aplicação e as subclasses


+ Fábrica concreta para cada tipo de objeto
+ É fácil adicionar uma nova família de objetos

- Difícil adicionar um novo objeto na família


<<interface>> E se tivermos que criar
ConsultaBD
UpdateBD,
executar(…)
DeleteBD,
InsertBD?

ConsultaOracle ConsultaSQLServer

executar(…) executar(…)
problema
public void colocarInfoCarrinho(HTTPServletRequest request){
Carrinho c = CookieFactory.criarCarrinho(request);

if (c !=null)
request.setAttribute("valor",c.getValor());
else
request.setAttribute("valor",0);

if (request.getAttribute("username")==null){
if (c !=null)
request.setAttribute("user",c.getNome());
else
request.setAttribute(“user",
"<a href=login.jsp>Login</a>");

}else{
request.setAttribute(“user",
request.getAttribute("username"));
}
public class CarrinhoNulo extends Carrinho {

public double getValor() {


return 0.0;
}

public String getNome() {


return "<a href=login.jsp>Login</a>";
}

}
Padrão Null Object
public class CarrinhoNulo extends Carrinho {

public double getValor() {


return 0.0;
}

public String getNome() {


return "<a href=login.jsp>Login</a>";
}

}
padrão Null Object
public void colocarInfoCarrinho(HTTPServletRequest request){

Carrinho c = CookieFactory.criarCarrinho(request);

request.setAttribute("valor",c.getValor());

if (request.getAttribute("username")==null){
request.setAttribute("user",c.getNome());
}else{
request.setAttribute("user",request.getAttribute("username"));
}
}
Consequências

+ resolve o problema do tratamento de


valores nulos em qualquer ponto da
aplicação que utilize a classe
+ cliente não é modificado

- tratamento de valores nulos não fica


explicito podendo gerar uma certa
confusão
serialização

pós-
processamento
Método de serialização

Método de pós-
processamento
Problema: E se quisermos gerar arquivos XML
criptografados e de propriedades compactados?

GeradorArquivo

gerarArquivo(…)
abstract gerarConteudo (…)
hook methods
processar (…)

GeradorXMLCompactado GeradorPropriedadesCriptografado

gerarConteudo (…) gerarConteudo (…)


processar (…) processar (…)
GeradorArquivo

gerarArquivo(…)
abstract gerarConteudo (…)
processar (…)

GeradorCriptografado GeradorXMLCompactado

gerarConteudo (…) gerarConteudo (…)


processar (…) processar (…)

GeradorPropCriptog. GeradorXMLCriptog.

dup.
gerarConteudo (…) gerarConteudo (…) código
GeradorArquivo

gerarArquivo(…)
abstract gerarConteudo (…)
processar (…)

GeradorPropriedadesCriptografado GeradorXML

gerarConteudo (…) gerarConteudo (…)


processar (…) processar (…)

GeradorXMLCriptog. GeradorXMLCompact.

dup. processar (…) processar (…)

código
Bridge
Cria uma ponte entre duas hierarquias ligadas por uma relação de composição
permitindo que ambas variem de forma independente

<<interface>>
GeradorArquivo
Pós-processador
posProcessador

gerarArquivos
gerarConteudo (…) processar (…)

GeradorXML GeradorProp. Compactador Criptografado

gerarConteudo gerarConteudo processar (…) processar (…)


Problema:
E o caso em que não há pós-processamento?

<<interface>>
GeradorArquivo
Pós-processador
posProcessador

gerarArquivos
gerarConteudo (…) processar (…)

GeradorXML GeradorProp. Compactador Criptografado

gerarConteudo gerarConteudo processar (…) processar (…)


Consequências

+ Desacoplamento aumenta a capacidade de reuso e


extensão
* tornam independentes os fatores que podem variar
na solução
* as classes que foram separadas também podem ser
usadas em outros contextos
+ Ocultam detalhes de implementação dos clientes

- aumento do número de classes


- aumento da complexidade na criação do objeto
Exercício:
Como melhorar este design?
Problema: Criar uma aplicação para
mostrar em tempo real o resultado da
apuração de uma eleição. O resultado deve
ser mostrado em tabelas e gráficos.
public class ResultadoVotacao {

private HashMap<String,Integer> votosApurados;


private Grafico grafico;
private Tabela tabela;

public void atualizarVotos(HashMap<String, Integer> votosApurados) {


this.votosApurados = votosApurados;
grafico.atualizar(votosApurados);
tabela.atualizar(votosApurados);
}

}

ResultadoVotação está acoplado a Grafico e Tabela.

E se quisermos mostrar o resultado em vários gráficos e/


ou tabelas? Ou usarmos outra representação para
apresentar o resultado?
public class ResultadoVotacao {

private HashMap<String,Integer> votosApurados;


private Grafico grafico1;
private Grafico grafico2;
i m
ru
private Grafico grafico3;
private Grafico grafico4;
i g n
private Tabela tabela1;
es
private
private
Tabela tabela2;
Imagem imagem; D
public void atualizarVotos(HashMap<String, Integer> votosApurados) {
this.votosApurados = votosApurados;
grafico1.atualizar(votosApurados);
grafico2.atualizar(votosApurados);
grafico3.atualizar(votosApurados);
grafico4.atualizar(votosApurados);
tabela1.atualizar(votosApurados);
tabela2.atualizar(votosApurados);
imagem.atualizar(votosApurados);
}

}
Observer Reduz acoplamento
Permite adicionar outras representações

ResultadoVotacao <<interface>>
RepresentacaoResultado
representacoes
addRepResultado(rep) atualizar(…)
atualizarVotos(votos)
notificar()

Grafico Tabela
for rep in representacoes
rep.atualizar(…)
atualizar(…) atualizar(…)
Observer: Solução
Composição de um com múltiplos objetos
É aplicável quando existe um objeto cujos eventos
precisam ser observados por outros objetos
Consequências

+ permite que objetos registrem dinamicamente


suas dependências de outros objetos
+ permite atualizar um conjunto de objetos quando
um certo objeto sofrer modificação

- a possibilidade de demora na execução de um


observador pode influenciar a velocidade de
notificação dos outros
Onde esse código Java usa o padrão
Observer?

Button button = new Button(shell, SWT.PUSH);

//register listener for the selection event


button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
//aqui ocorre o evento quando o botão recebeu a ação
}
});
Exercício:

Modele uma aplicação que divulga notícias para


todos os seus assinantes, que podem ser
assinantes por e-mail ou por SMS.
Variando o comportamento
com o estado da classe
DFS
Se cor == branco estado
cor = cinza comportamento

Se cor == cinza estado


visita nós adjacentes comportamento
cor == preto

Se cor == preto estado


adiciona nó comportamento
Problema: muitos “ifs" no código para checar
o estado e definir o comportamento

Se cor == branco estado


cor = cinza comportamento

Se cor == cinza estado


visita nós adjacentes comportamento
cor == preto

Se cor == preto estado


adiciona nó comportamento
No
adjacentes
cor
buscaProfundidade (…)
setCor (…)
addAdjacente (…)
No Cor
adjacentes
cor
buscaProfundidade (…) visita (…)
setCor (…) busca (…)
addAdjacente (…)
No Cor
adjacentes
cor
buscaProfundidade (…) visita (…)
setCor (…) busca (…)
addAdjacente (…)

Branco Cinza Preto

visita (…) busca (…) busca (…)


No Cor
adjacentes
cor
buscaProfundidade (…) visita (…)
setCor (…) busca (…)
addAdjacente (…)

Branco Cinza Preto

visita (…) busca (…) busca (…)

comportamento
- muda cor para cinza - adiciona nó
é alterado em
função do
estado (cor) do - visita nós adjacentes
objeto (nó) - muda cor para preto
State
Permite a mudança de estado de um objeto dinamicamente
Mais util ainda quando a mudança de estado provoca um comportamento
diferente
Subclasses de State representam comportamento variável
Consequências

+ Mudança de estado e adição de novos estados


ficam diretas
+ Mais um caso de delegação em vez de herança
+ Uso avançado de polimorfismo

- Uma subclasse de state terá conhecimento de


pelo menos uma outra, o que aumenta o
acoplamento entre as subclasses
Exercício
Comportamento correto, mas
assinaturas indesejáveis

116
Adapter
Adapter
Adapter
Adapter
Adapter
Solução
Utilizar uma classe ou mais classes que adaptam a classe alvo para
ser usada
Clientes da figura e a implementação de círculo ficam totalmente
independentes
A classe adaptadora permite separação que traz qualidade de
software
Consequências

+ Objetos podem ser reusados através de uma


readaptação de suas interfaces
+ Cliente não é afetado

- Aumento no número de classes e interfaces

Das könnte Ihnen auch gefallen