Você está na página 1de 96

Padrões de Projeto

LIVRO 04
Padrões Gang of Four
Sumário
1. Padrões Gang of Four 4. Padrões GoF comportamentais
2. Padrões GoF de criação Chain of responsability
Command
Abstract Factory
Iterator
Builder
Mediator
Prototype
Memento
Singleton
Observer
3. Padrões GoF estruturais State
Strategy
Object Adapter
Visitor
Bridge
Composite 5. Referências
Decorator
Facade
Flyweight
Proxy
Padrões Gang of Four Frameworks

Atualmente a codificação para sistemas corporativos


está toda baseada em frameworks.
Frameworks são uma coleção de classes abstratas,
objetos e padrões dedicados a resolver determinados
problemas em uma arquitetura flexível e extensível.
Conhecer esses padrões é fundamental para entender
os modernos frameworks e desenvolver softwares de
qualidade que buscam os melhores resultados da
orientação a objetos.
Frameworks front­end: Bootstrap, foundation, materialize.
Frameworks back­end: laravel (PHP), CodeIgniter (PHP),
Rails (Ruby), .Net Framework (.Net), Django (Python),
Express (Node.js), Ionic (mobile), Struts (Java)
Frameworks para Javascript: Angular e Vue.js

1 2 3 4 5 6 7 8 9 10
Padrões Gang of Four História

Em 1995, um grupo de quatro profissionais escreveu e lançou o


livro "Design Patterns”, um catálogo com 23 padrões de desenho.
O grupo passou a ser chamado de Gangue dos Quatro: Erich
Gamma, Richard Helm, Ralph Johnson, e John Vlissides.

1 2 3 4 5 6 7 8 9 10
Padrões Gang of Four
O Padrão GoF é um repertório de soluções e princípios que ajudam os desenvolvedores a criar
software, e que são codificados em um formato estruturado, consistindo de: nome, problema e
solução.
Todo padrão GoF possui então os seguintes atributos:
• Nome – descreve a essência do padrão
• Problema que soluciona – descreve quando aplicar o padrão, e em qual condições
• Solução do problema – descrição abstrata de como usar as classes e objetos para
solucionar o problema
Podemos ainda incluir:
• Exemplos – uma ou mais figuras, diagramas ou descrições que ilustrem um protótipo de
aplicação
• Consequência – custo, benefícios e impacto ao se aplicar o padrão no sistema

1 2 3 4 5 6 7 8 9 10
Padrões Gang of Four
Os padrões GoF estão classificados em:
Padrão de Criação
• Relacionados à criação de classes e
objetos.
• Ligados ao processo de instanciação.
Padrão Estrutural
• Tratam da alteração da estrutura de
um programa, e das associações entre
classes e objetos.
Padrão Comportamental
• Observam a maneira com que classes
e objetos podem interagir.

1 2 3 4 5 6 7 8 9 10
Padrões Gang of Four

1 2 3 4 5 6 7 8 9 10
O conceito de Fábrica (Factory)
Se refere a uma função, método ou classe que deve produzir alguma coisa.
Produzem objetos e também podem produzir arquivos, registros em bases de dados, entre outros.
Um dos padrões de projeto criacionais.
Geralmente, quando alguém diz uma palavra “fábrica”, o significado exato deve ficar claro a partir
de um contexto.
Exemplos:
­ Uma função ou método que cria a interface de um programa;
­ Uma classe que cria usuários;
­ Um método estático que chama uma classe construtora de uma certa maneira;

1 2 3 4 5 6 7 8 9 10
O conceito de Fábrica Simples (Simple Factory)

Esse padrão descreve uma classe que tem um método de criação com uma condicional que,
baseada nos parâmetros do método, escolhe qual classe produto instanciar e retornar.
É comum confundir fábricas simples com fábricas gerais ou com um dos padrões de projeto
criacional.
Comumente uma fábrica simples é uma etapa intermediária na introdução dos padrões Factory
Method ou Fábrica Abstrata.
O Factory Method é um padrão de projeto criacional que fornece uma interface para criação de
objetos, mas permite que subclasses alterem o tipo de um objeto que será criado.
Fábricas simples geralmente não têm subclasses. Mas após extrair subclasses de uma fábrica simples,
ela começa a se parecer como um padrão Factory Method.

1 2 3 4 5 6 7 8 9 10
Fábrica simples Diagrama
Conceitual

Produto1

Cliente Factory ClasseAbstrata

Criando_tipo(tipo) Produto2

1 2 3 4 5 6 7 8 9 10
Fábrica Simples Implementação
Passo 1: implemente as classes Passo 2: implemente a fábrica Passo 3: implemente o executor
A classe abstrata e as classes Aqui fica a lógica que define Esta classe testa a execução
concretas. qual classe será instanciada. da fábrica.

public abstract class Pessoa { class FactoryPessoa { public class TesteApp {


public String nome; public Pessoa getPessoa(String nome, String sexo) { public static void main(String args[]) {
public String sexo;
if (sexo.equals("M")) FactoryPessoa factory = new FactoryPessoa();
} return new Homem(nome);
String nome = "Carlos";
class Homem extends Pessoa { if (sexo.equals("F"))
return new Mulher(nome); String sexo = "H";
public Homem(String nome) { }
this.nome = nome; factory.getPessoa(nome, sexo);
System.out.println("Olá Senhor " + this.nome); }
} }
} }
class Mulher extends Pessoa {
public Mulher(String nome) {
this.nome = nome;
System.out.println("Olá Senhora " + this.nome);
}
}

1 2 3 4 5 6 7 8 9 10
Abstract Factory Caso de Uso
O que é? Quando usar? Vantagens
Possibilita a criação de famílias de objetos Um sistema deve ser independente Possibilita a criação de famílias de objetos
relacionados ou dependentes por meio de de como os seus produtos são relacionados ou dependentes por meio de
uma única interface e sem especificar uma uma única interface e sem que a classe
classe concreta. criados, compostos ou
concreta seja especificada.
representados
Utiliza o princípio de Polimorfismo, permitindo O objetivo é isolar a criação de objetos
uma aplicação totalmente adaptável às Um sistema deve ser configurado de seu uso e criar famílias de objetos
mudanças de forma transparente. como um produto de uma família de relacionados sem ter que depender de
Muitas frameworks e bibliotecas Java utilizam múltiplos produtos suas classes concretas, permitindo novos
para fornecer uma maneira de estender e tipos derivados de serem introduzidos sem
personalizar seus componentes padrão. Uma família de objetos for projetada qualquer alteração ao código que usa a
Sempre temos um objeto fábrica, que é para ser usada em conjunto, e você classe base
usada para criar subcomponentes precisa garantir essa restrição Permite utilizar apenas classes abstratas ou
específicos.
Você quer fornecer uma biblioteca interfaces, diminuindo muito o acoplamento
Pode ser aplicado em cenários onde uma entre as classes do sistema, permitindo
família de produtos ou classes precisa ser de classes e quer relevar somente também adicionar, modificar ou remover
instanciado, sem dependência de suas suas interfaces, não suas produtos da família de forma rápida.
classes concretas. implementações

1 2 3 4 5 6 7 8 9 10
Abstract Factory Diagrama
Conceitual

ProdutoB1 ClasseAbstrataB ConcreteFactoryA ProdutoA1

AbstractFactory
Criando_tipo(tipo)

ConcreteFactoryB ClasseAbstrataA
ProdutoB2 ProdutoA2

Criando_tipo(tipo)

1 2 3 4 5 6 7 8 9 10
Abstract Factory Implementação
Passo 1: implemente as interfaces Passo 2: implemente as classes concretas
Estas interfaces vão definir como serão os tipos de Estas classes vão ser criadas pelas fábricas.
carro.

public interface CarroSedan { public class Siena implements CarroSedan {


void exibirInfoSedan(); @Override
} public void exibirInfoSedan() {
System.out.println("Modelo: Siena\nFábrica: Fiat\nCategoria:Sedan");
}
}

public interface CarroPopular { public class Palio implements CarroPopular {


void exibirInfoPopular(); @Override
} public void exibirInfopopular() {
System.out.println("Modelo: Palio\nFábrica: Fiat\nCategoria:Popular");
}
}

1 2 3 4 5 6 7 8 9 10
Abstract Factory Implementação
Passo 3: implemente a fábrica abstrata Passo 5: implemente a execução
Agora vamos colocar todas as fábricas para
public interface FabricaDeCarro { funcionar.
CarroSedan criarCarroSedan();
CarroPopular criarCarroPopular(); public class AbstractFactory {
}
public static void main(String[] args) {
FabricaDeCarro fabrica = new FabricaFiat();
CarroSedan sedan = fabrica.criarCarroSedan() {
Passo 4: implemente as fábricas concretas CarroPopular popular = fabrica.criarCarroPopular() {
sedan.exibirInfoSedan();
System.out.println():
public class FabricaFiat implements FabricaDeCarro { popular.exibirInfoPopular();
@Override System.out.println();
public CarroSedan criarCarroSedan() { }
}
return new SIena();
}
public CarroPopular criarCarroPopular() {
return new Palio();
}
}

1 2 3 4 5 6 7 8 9 10
Builder Caso de Uso
O que é? Estrutura Caso de Uso
É um padrão de projeto de ­Director: sua função é construir um Em um fast­food uma pessoa pediu um
objeto utilizando a interface do lanche ao atendente. Este, por sua vez,
software que permite a separação
builder; repassa o pedido para a cozinha, onde
da construção de um objeto o lanche é produzido. Quando pronto,
complexo da sua representação, ­Builder: detalha uma interface para o lanche é entregue ao atendente e,
de forma que o mesmo processo um construtor de partes do objeto­ por fim, a pessoa que pediu. Nesse
produto; pequeno cenário, observa­se:
de construção possa criar
diferentes representações. ­ConcreteBuilder: ajusta uma ­O atendente é apenas um
implementação da interface builder, intermediário entre o cliente e a cozinha
Builder não é usado apenas para mantendo a representação que cria e
construir objetos complexos. Ele ­O atendente não sabe como o lanche
fornece interface para recuperação
permite que diferentes é feito. Apenas repassa o pedido do
do produto;
cliente;
representações possam ser ­Product: é a última etapa, sendo o
construídos com a mesma ­O lanche é feito pelo cozinheiro,
objeto complexo construído. Nele enquanto o atendente apenas o espera
sequência de passos. possui as classes que definem as pronto.
partes que o compõem;

1 2 3 4 5 6 7 8 9 10
Builder Diagrama
Conceitual
Exemplo em termos técnicos
­ O atendente é o Director,
que solicita a construção de
um objeto (produto); Director Builder ConcreteBuilder

­ O lanche é o Product, ou builder: Builder

seja, o produto resultante da buildPart()


construct()
construção; buildPart() getResult() : Product

­ O quadro de funcionários
que fazem os lanches é o Produto
Builder (Interface);
­ O cozinheiro que preparou
o lanche pedido é o
Concrete Builder (objeto).

1 2 3 4 5 6 7 8 9 10
Builder Implementação
Passo 1: implemente a classe Casa Passo 2: implemente a classe construtora da casa
e a classe Engenheiro
Esta classe é a base para o padrão builder.

package builderexemplo; package builderexemplo; package builderexemplo;


public class Casa { public interface CasaBuilder { public class Engenheiro {
private String alicerce; void construirAlicerce(); private CasaBuilder casaBuilder;
private String estrutura; void construirEstrutura();
private String telhado; void construirTelhado(); public Engenheiro(CasaBuilder casaBuilder) {
private boolean decoracao; void pintarCasa(); this.casaBuilder = casaBuilder;
private boolean pintura; void decorarCasa(); }
Casa getCasa();
public void setAlicerce(String alicerce) { this.alicerce = alicerce; } } public Casa construirCasa() {
public void setEstrutura(String estrutura) { this.estrutura = estrutura; } this.casaBuilder.construirAlicerce();
public void setTelhado(String telhado) { this.telhado = telhado; } this.casaBuilder.construirEstrutura();
public void setDecoracao(boolean decoracao) { this.decoracao = decoracao; } this.casaBuilder.construirTelhado();
public void setPintura(boolean pintura) { this.pintura = pintura; } this.casaBuilder.pintarCasa();
this.casaBuilder.decorarCasa();
@Override return this.casaBuilder.getCasa();
public String toString() { }
return "Alicerce - "+ alicerce + "\nEstrutura - "+ estrutura + }
"\nTelhado - "+ telhado + "\nEstá decorada? - " + decoracao +
"\nEstá pintada? - " + pintura;
}
}

1 2 3 4 5 6 7 8 9 10
Builder Implementação
Passo 3: implemente a classe construtora CasaMadeiraBuilder

package builderexemplo; @Override


public void pintarCasa() {
public class CasaMadeiraBuilder implements CasaBuilder { casa.setPintura(true);
private Casa casa; System.out.println("CasaMadeiraBuilder: Pintura concluída...."); }
public CasaMadeiraBuilder() { this.casa = new Casa(); } @Override
public void decorarCasa() {
@Override casa.setDecoracao(true);
public void construirAlicerce() { System.out.println("CasaMadeiraBuilder: Decoração concluída...."); }
casa.setAlicerce("Concreto, tijolos e pedra");
System.out.println("CasaMadeiraBuilder: Alicerce concluído..."); } @Override
public Casa getCasa() {
@Override System.out.println("CasaMadeiraBuilder: Casa de madeira concluída...");
public void construirEstrutura() { return casa;
casa.setEstrutura("Madeira"); }
System.out.println("CasaMadeiraBuilder: Estrutura concluída..."); }
}
@Override
public void construirTelhado() {
casa.setTelhado("Madeira e telhas");
System.out.println("CasaMadeiraBuilder: Telhado concluído...."); }

1 2 3 4 5 6 7 8 9 10
Builder Implementação
Passo 4: implemente a classe construtora CasaConcretoBuilder

package builderexemplo; @Override


public void pintarCasa() {
public class CasaConcretoBuilder implements CasaBuilder { casa.setPintura(true);
private Casa casa; System.out.println("CasaConcretoBuilder: Pintura concluída...."); }
public CasaConcretoBuilder() { @Override
this.casa = new Casa(); public void decorarCasa() {
} casa.setDecoracao(true);
System.out.println("CasaConcretoBuilder: Decoração concluída...."); }
@Override
public void construirAlicerce() { @Override
casa.setAlicerce("Concreto, tijolos e pedra"); public Casa getCasa() {
System.out.println("CasaConcretoBuilder: Alicerce concluído..."); } System.out.println("CasaConcretoBuilder: Casa de concreto concluída...");
return this.casa;
@Override }
public void construirEstrutura() {
casa.setEstrutura("Concreto, argamassa, tijolos e vergalhões"); }
System.out.println("CasaConcretoBuilder: Estrutura concluída..."); }
@Override
public void construirTelhado() {
casa.setTelhado("Concreto, vergalhões e telhas");
System.out.println("CasaConcretoBuilder: Telhado concluído...."); }

1 2 3 4 5 6 7 8 9 10
Builder Implementação
Passo 5: implemente a classe TesteConstrução Casa
package builderexemplo;
Esta classe vai executar a situação depois da public class TesteConstrucaoCasa {
implementação do padrão. public static void testeConstruirCasa() throws Exception {
CasaBuilder casaConcretoBuilder = new CasaConcretoBuilder();
Engenheiro engenheiroA = new Engenheiro(casaConcretoBuilder);
Casa casaA = engenheiroA.construirCasa();
System.out.println("Casa construída: "+casaA);
CasaBuilder casaMadeiraBuilder = new CasaMadeiraBuilder();
Engenheiro engenheiroB = new Engenheiro(casaMadeiraBuilder);
Casa casaB = engenheiroB.construirCasa();
System.out.println("Casa construída: "+casaB);
}
public static void main(String[] args) {
try {
testeConstruirCasa();
} catch (Exception e) {
System.err.println(e);
}
}
}

1 2 3 4 5 6 7 8 9 10
Prototype Caso de Uso
O que é? Quando usar? Caso de uso
O Prototype permite a criação de ­ Evitar que as subclasses que criam Temos um objeto e queremos criar uma
novos objetos a partir de um objetos funcionem como o padrão cópia exata dele. Temos que criar um novo
objeto da mesma classe, e, em todos os
modelo original ou protótipo, que abstract factory;
campos do objeto original, copiamos seus
é clonado. ­ Evitar criar um novo objeto valores para o novo objeto.
utilizando a palavra new, o que Mas e se alguns campos do objeto são
diminui o custo de memória. privados e não estão visíveis fora do
próprio objeto?
­ Basicamente, em vez de o cliente
implementar um código que utiliza o O Prototype delega o processo de
clonagem para o próprio objeto que está
operador new, este utiliza o método sendo clonado. O padrão declara uma
clone() presente no protótipo e o interface comum para todos os objetos
método de uma fábrica (Factory que suportam clonagem. Essa interface
Method ou Abstratct Factory) que permite que você clone um objeto sem
fica encarregada de clonar o novo acoplar seu código à classe daquele
objeto. Geralmente, tal interface contém
objeto.
apenas um único método clonar.

1 2 3 4 5 6 7 8 9 10
Prototype Diagrama
Conceitual

palioNovo

Clonar()
CarroPrototype

palioUsado

Clonar()

1 2 3 4 5 6 7 8 9 10
Prototype Implementação
Passo 1: implemente o protótipo Passo 2: implemente um protótipo para o Fiesta
A classe abstrata CarroPrototype vai definir
como serão os carros reais. package trabalho.prototype.carro;
public class FiestaPrototype extends CarroPrototype {
package trabalho.prototype.carro; protected FiestaPrototype(FiestaPrototype fiestaPrototype) {
this.valorCompra = fiestaPrototype.getValorCompra();
public abstract class CarroPrototype { }
protected double valorCompra; public FiestaPrototype() {
valorCompra = 0.0;
public abstract String exibirInfo(); }
public abstract CarroPrototype clonar(); @Override
public String exibirInfo() {
public double getValorCompra() { return "Modelo: Fiestan\nMontadora: Fordy\n" + "Valor: R$" + getValorCompra();
return valorCompra; }
} @Override
public void setValorCompra(double valorCompra) { public CarroPrototype clonar() {
this.valorCompra = valorCompra; return new FiestaPrototype(this);
} }
} }

1 2 3 4 5 6 7 8 9 10
Prototype Implementação
Passo 3: implemente a execução do protótipo

package trabalho.prototype.carro;
public class TrabalhoPrototypeCarro {
public static void main(String[] args) {
FiestaPrototype prototipoPalio = new FiestaPrototype();
CarroPrototype palioNovo = prototipoPalio.clonar();
palioNovo.setValorCompra(27900.0);
CarroPrototype palioUsado = palioNovo.clonar();
System.out.println("= TESTE 1 ==============================");
System.out.println(palioNovo.exibirInfo());
System.out.println("=======================================");
System.out.println(palioUsado.exibirInfo());
palioUsado.setValorCompra(23000);
System.out.println("\n\n= TESTE 2 ==============================");
System.out.println(palioNovo.exibirInfo());
System.out.println("=======================================");
System.out.println(palioUsado.exibirInfo());
}
}

1 2 3 4 5 6 7 8 9 10
Singleton Caso de Uso
O que é? Quando usar?
O Singleton é um padrão de Garantir que uma classe tenha apenas uma única instância. A razão
projeto criacional, que garante mais comum para isso é para controlar o acesso a algum recurso
que apenas um objeto desse tipo compartilhado—por exemplo, uma base de dados ou um arquivo.
exista e forneça um único ponto
Fornece um ponto de acesso global para aquela instância. Embora
de acesso a ele para qualquer
sejam muito úteis, elas também são muito inseguras uma vez que
outro código.
qualquer código pode potencialmente sobrescrever os conteúdos
daquelas variáveis e quebrar a aplicação.Assim como uma variável
global, o padrão Singleton permite que você acesse algum objeto de
qualquer lugar no programa. Contudo, ele também protege aquela
instância de ser sobrescrita por outro código.

1 2 3 4 5 6 7 8 9 10
Singleton Implementação
Passo 1: implemente a classe Reitor Passo 2: implemente um protótipo para o Fiesta
Só pode ter um reitor, portanto tornaremos o
Reitor estático, seguindo o padrão. public class Main {
public static void main(String[] args) {
Reitor reitor1 ,reitor2, reitor3;
public class Reitor { //reitor1 = new Reitor();
private String nome;
private Reitor(){} reitor2 = Reitor.obterInstancia();
private static Reitor reitor = new Reitor(); reitor2.setarNome("João");
public static synchronized Reitor obterInstancia(){ reitor3 = Reitor.obterInstancia();
return reitor;
} if (reitor2 == reitor3) {
public String obterNome(){ System.out.println("Mesmo reitor");
return reitor.nome; System.out.println("Nome do reitor 2 = " + reitor2.obterNome());
} System.out.println("Nome do reitor 3 = " + reitor3.obterNome());
}
public void setarNome(String nome){ }
}
this.nome = nome;
}
}

1 2 3 4 5 6 7 8 9 10
Object Adapter Caso de Uso
É um padrão de projeto estrutural, que permite a colaboração de objetos incompatíveis. Ele captura chamadas
para um objeto e as deixa reconhecíveis tanto em formato como interface para um segundo objeto.

O Padrão Adapter converte uma interface de uma classe para outra interface que o cliente espera encontrar
(permite que classes com interfaces incompatíveis trabalhem juntas). É um intermediador que recebe solicitações do
cliente e converte essas solicitações num formato que o fornecedor entenda.

É muito utilizado quando precisamos encaixar uma nova biblioteca de classes, adquirida de um fornecedor já
existente, porém as bibliotecas do novo fornecedor são diferentes das bibliotecas do fornecedor antigo.

Como não temos o código do novo fornecedor e também não podemos alterá­la, o que pode ser feito é criar uma
classe que faça essa adaptação, ou seja, ela é responsável por adaptar a interface do novo fornecedor ao
formato que o sistema espera.

É muito utilizado para compatibilizar o seu sistema a outros frameworks ou APIs.

1 2 3 4 5 6 7 8 9 10
Object Adapter Diagrama
Conceitual

Cliente Destino Adaptador Adaptado

PedidoEspecífico()
pedido() pedido()

1 2 3 4 5 6 7 8 9 10
Object Adapter Implementação
Passo 1: implemente as tomadas Passo 2: implemente o adaptador
Temos a tomada dois pinos e a tomada tres pinos. Esta classe vai fazer a ligação entre a tomada de
dois pinos e a tomada de tres pinos.

public class TomadaDeDoisPinos { public class AdapterTomada extends TomadaDeDoisPinos {


public void ligarNaTomadaDeDoisPins() { private TomadaDeTresPinos tomadaDeTresPinos;
System.out.prinln("Ligado na Tomada de Dois Pinos");
} public AdapterTomada(TomadaDeTresPinos tomadaDeTresPinos) {
}
this.tomadaDeTresPinos = tomadaDeTresPinos;
public class TomadaDeTresPinos {
}
public void ligarNaTomadaDeTresPins() {
System.out.prinln("Ligado na Tomada de Tres Pinos"); public void ligarNaTomadaDeDoisPinos() {
}
} tomadaDeTresPinos.ligarNaTomadaDeTresPinos();
}
}

1 2 3 4 5 6 7 8 9 10
Object Adapter Implementação
Passo 3: executanddo o padrão
Ligando uma tomada de 3 pinos em uma tomada
de 2 pinos.

public class Teste {


public static void main(String args[]) {
TomadaDeTresPinos t3 = new TomadaDeTresPinos();
AdapterTomada a = new AdapterTomada(t3);
a.ligarNaTomadaDeDoisPinos();
}
}

1 2 3 4 5 6 7 8 9 10
Bridge Caso de Uso
Bridge é utilizado quando queremos separar a abstração da implementação, é considerado um padrão estrutural.

­ Evita uma ligação permanente entre uma abstração e implementação;


­ Protege o cliente das alterações de implementações;
­ Esconde completamente uma implementação do cliente;
­ Possui menor complexidade para organizar hierarquias ;

Bridge facilita quando temos uma quantidade grande de hierarquias e extensões, logo simplifica o uso das
implementações, isolando elas do cliente, assim como uma melhor separação entre abstração e implementação.

1 2 3 4 5 6 7 8 9 10
Bridge Diagrama
Conceitual

­Abstraction: Esta é uma classe abstrata que


contém os membros que definem a abstração de
negócios e suas funcionalidades. Contém uma
referência para o objeto do tipo Bridge. Também é
responsável por ser a classe base para outras
abstrações.
­Redefined Abstraction: classe que herda da classe
Abstraction, estendendo a interface definida por ela.
­Bridge: Esta é uma interface que age como uma
ponte entre a classe de abstração e de
implementação, e também tem a funcionalidade de
tornar a classe de implementação independente da
classe de abstração.
­Implementation: classes tem como objetivo
implementar a interface Bridge e também
responsáveis por exibir os detalhes de
implementação para a abstração associada a
ponte.

1 2 3 4 5 6 7 8 9 10
Bridge Implementação
Passo 1: implemente a classe abstrata Passo 2: implemente as classes concretas
package bridgeexemplo;
package bridgeexemplo;
public class MensagemEmail extends Mensagem{
public abstract class Mensagem {
public MensagemEmail(ServicoMensagem servicoMensagem) {
ServicoMensagem servicoMensagem; super(servicoMensagem);
}
public Mensagem (ServicoMensagem servicoMensagem) { @Override
public void enviar() {
this.servicoMensagem = servicoMensagem; servicoMensagem.enviarMensagem();
} }
}
abstract public void enviar();
}
package bridgeexemplo;
public class MensagemTexto extends Mensagem{
public MensagemTexto(ServicoMensagem servicoMensagem) {
super(servicoMensagem);
}
@Override
public void enviar() {
servicoMensagem.enviarMensagem();
}
}

1 2 3 4 5 6 7 8 9 10
Bridge Implementação

Passo 3: implemente a interface do serviço Passo 4: implemente as classes concretas do serviço

package bridgeexemplo; package bridgeexemplo;


public interface ServicoMensagem { public class ServicoMensagemEmail implements ServicoMensagem{
public void enviarMensagem();
} @Override
public void enviarMensagem() {
System.out.println("ServicoMensagemEmail: Enviando email...");
}
Passo 5: implemente o executor }

package bridgeexemplo;
public class TesteMensagem {
package bridgeexemplo;
public static void main(String[] args) {
ServicoMensagem servicoMensagemTexto = new ServicoMensagemTexto(); public class ServicoMensagemTexto implements ServicoMensagem{
Mensagem mensagemTexto = new MensagemTexto(servicoMensagemTexto);
mensagemTexto.enviar(); @Override
public void enviarMensagem() {
ServicoMensagem servicoMensagemEmail = new ServicoMensagemEmail(); System.out.println("ServicoMensagemTexto: Enviando mensagem de texto...");
Mensagem mensagemEmail = new MensagemEmail(servicoMensagemEmail); }
mensagemEmail.enviar(); }
}
}

1 2 3 4 5 6 7 8 9 10
Composite Caso de Uso

Esse padrão de projetos pode ser visto como uma estrutura de árvore
composta de tipos que herdam um tipo base e pode representar uma
única parte ou toda uma hierarquia de objetos.
Este padrão pode ser dividido em:
Componente – é a interface base para todos os objetos na
composição. Deve ser uma interface ou uma classe abstrata com os
métodos comuns para gerenciar os compostos filhos.
Folha – implementa o comportamento padrão do componente base. Ele
não contém uma referência aos outros objetos.
Composto – tem elementos folha. Ele implementa os métodos do
componente base e define as operações relacionadas ao filho.
Cliente – tem acesso aos elementos de composição usando o objeto
componente base.

1 2 3 4 5 6 7 8 9 10
Composite Diagrama
Conceitual

DepartVendas

<<interface>> DepartChefe
Departamento

printNomeDepart
DepartFinanceiro

1 2 3 4 5 6 7 8 9 10
Composite Implementação

Passo 1: implemente a interface Departamento Passo 2: implemente a classe DepartamentoVendas


Esta interface contem todas os métodos, ainda sem Esta classe contrata a interface Departamento, o que
a implementação do padrão. obriga a classe DepartamentoVendas a implementar
as ações.

package empresa.composite; package empresa.composite;


public interface Departamento public class DepartamentoVendas implements Departamento {
{ private Integer id;
void printNomeDepart(); private String name;
}
public DepartamentoVendas(Integer id, String name) {
this.id = id;
this.name = name;
}
public void printNomeDepart() {
System.out.println(getClass().getSimpleName()); }
public Integer getId() { return id; }
public String getName() { return name; }
public void setId(Integer id) { this.id = id; }
public void setName(String name) { this.name = name; }
}

1 2 3 4 5 6 7 8 9 10
Composite Implementação

Passo 3: implemente a classe Passo 4: implemente a classe DepartamentoChefe


DepartamentoFinanceiro
Esta classe contrata a interface Departamento, e terá
Esta classe contrata a interface Departamento, o que
como atributo uma lista de departamentos
obriga a classe DepartamentoFinanceiro a
implementar as ações. package empresa.composite;
import java.util.ArrayList;
import java.util.List;
package empresa.composite;
public class DepartamentoChefe implements Departamento {
public class DepartamentoFinanceiro implements Departamento {
private Integer id;
private Integer id; private String name;
private String name; private List<Departamento> childDepartments;
public DepartamentoFinanceiro(Integer id, String name) { public DepartamentoChefe(Integer id, String name) {
this.id = id; this.id = id;
this.name = name; this.name = name;
} this.childDepartments = new ArrayList<Departamento>(); }
public void printNomeDepart() { public void printNomeDepart() {
System.out.println(getClass().getSimpleName()); } childDepartments.forEach(Departamento::printNomeDepart); }
public Integer getId() { return id; } public void addDepartMent(Departamento departamento) {
public String getName() { return name; } childDepartments.add(departamento); }
public void setId(Integer id) { this.id = id; } public void removeDepartment(Departamento departamento) {
public void setName(String name) { this.name = name; } childDepartments.remove(departamento); }
} }

1 2 3 4 5 6 7 8 9 10
Composite Implementação

Passo 5: implemente a classe executora


Esta classe instancia os departamentos.

package empresa.composite;
public class EmpresaComposite {
public static void main(String args[])
{
Departamento DepartamentoVendas = new DepartamentoVendas(1 , "Departamento de Vendas");
Departamento DepartamentoFinanceiro = new DepartamentoFinanceiro(2, "Departamento Financeiro");
DepartamentoChefe departamentoChefe = new DepartamentoChefe(3, "Departamento Chefe");
departamentoChefe.addDepartMent(DepartamentoVendas);
departamentoChefe.addDepartMent(DepartamentoFinanceiro);
departamentoChefe.printNomeDepart();
}
}

1 2 3 4 5 6 7 8 9 10
Decorator Caso de Uso

Pesquisa a ser realizada pelos alunos.

1 2 3 4 5 6 7 8 9 10
Decorator Diagrama
Conceitual

Pesquisa a ser realizada pelos alunos.

1 2 3 4 5 6 7 8 9 10
Decorator Implementação

Pesquisa a ser realizada pelos alunos.

1 2 3 4 5 6 7 8 9 10
Facade Caso de Uso

O Padrão Facade (tradução: fachada) fornece uma interface unificada para um conjunto de interfaces em um subsistema
(define uma interface de nível mais alto que facilita a utilização de um subsistema)
Este nome é uma analogia para uma fachada de arquitetura. Um Facade é um objeto que provê uma interface simplificada
para um corpo de código maior, como por exemplo, uma biblioteca de classes.
É do tipo estrutural, usado quando um sistema é muito complexo ou difícil de entender, já que possui um grande número de
classes independentes, ou se trechos de código­fonte estão indisponíveis.
Quando utilizar:
­ Quando se deseja uma interface simplificada para um subsistema muito complexo. Subsistemas comumente ficam mais
complexos a medida que evoluem e a maioria dos padrões, quando aplicados, resultam em muitas classes de pequeno
tamanho. Isso torna o subsistema mais reutilizável e simples de se customizar.
­ Quando existem muitas dependências entre clientes e classes de implementação.
­ Quando há o interesse em dividir os subsistemas em camadas. O facade pode definir um ponto de entrada para cada nível
de subsistema. Se seus subsistemas são dependentes, essas dependências podem ser simplificadas entre si ao se comunicarem
exclusivamente pelo facade.
­ Em uma situação que exista um sistema com diversas classes contendo diversos métodos e tenhamos que agrupar todas
essas classes chamando diversos métodos para realizar uma determinada operação. Com o Facade precisaríamos apenas
construir um método que agrupe todas essas classes e chame todos esses métodos.

1 2 3 4 5 6 7 8 9 10
Facade Diagrama
Conceitual

1 2 3 4 5 6 7 8 9 10
Facade Implementação

Passo 1: implemente a classe CPU Passo 2: implemente as classes HardDrive e Memoria


Esta classe irá compor uma classe maior. Estas classes irã compor uma classe maior.

package codigo;
public class HardDrive {
package codigo; public String read() {
System.out.println("Lê dados do HD"); return ""; }
public class CPU {
public void write() {
public void start() { System.out.println("Escreve dados no HD"); }
System.out.println("Inicialização inicial do processador");
} }
public void execute() {
System.out.println("Executa algo no processador"); package codigo;
}
public void load() { public class Memoria {
System.out.println("Carrega registradores"); public void load(String info) {
} System.out.println("Carrega dados na memória"); }
public void free() { public void free(String info) {
System.out.println("Libera registradores"); System.out.println("Libera dados da memória"); }
}
} }

1 2 3 4 5 6 7 8 9 10
Facade Implementação

Passo 3: implemente a classe Computador Passo 4: implemente a classe Executora


Esta classe será uma fachada para todas as O código comentado é a execução sem o padrão
classes anteriores, simplificando a execução Facade.

package codigo; package codigo;


public class ComputadorFacade { public class Codigo {
private CPU cpu = new CPU(); public static void main(String[] args) {
private Memoria memoria = new Memoria(); /*
private HardDrive hardDrive = new HardDrive(); CPU cpu = new CPU();
Memoria memoria = new Memoria();
public void ligarComputador() { HardDrive hardDrive = new HardDrive();
System.out.println("LIGANDO COMPUTADOR");
cpu.start(); ComputadorFacade facade = new ComputadorFacade(cpu, memoria, hardDrive);
String hdBootInfo = hardDrive.read(); */
memoria.load(hdBootInfo);
cpu.execute(); ComputadorFacade facade = new ComputadorFacade();
memoria.free(hdBootInfo); facade.ligarComputador();
} }
} }

1 2 3 4 5 6 7 8 9 10
Flyweight Caso de Uso

Flyweight é utilizado quando dentro do código possui uma grande quantidade de objetos que
devem ser tratados em memória, onde muitos deles possuem informações repetidas.
Para diminuir o alto consumo de memória pode ser criado um objeto que será compartilhado
inúmeras vezes.
Esse padrão de projetos é usado em casos muito específicos, por conta disso sua popularidade é
muito baixa. Entretanto não pode ser considerado como um padrão desprezado, pois ele é muito
utilizado principalmente em reutilizar objetos em processadores de texto e também é usado nos
exploradores de arquivo, que podem compartilhar objetos do mesmo tipo de arquivo para reduzir o
tempo de carga e exibição.
No exemplo a seguir será mostrado um programa na qual gerará círculos de diferentes cores e
posições.

1 2 3 4 5 6 7 8 9 10
Flyweight Diagrama
Conceitual

­FlyweightPatternDemo: exemplifica o cliente


que está utilizando a Factory, solicitando os
círculos e suas cores;
­ShapeFactory: possui um HashMap interno de
círculos, tendo como chave de identificação a
cor do círculo. Sempre que um novo círculo for
requisitado com uma cor específica, ele irá
verificar se já não construiu algum daquela
cor. Se sim, irá fornecer uma referência para a
o círculo já existente, caso contrário, irá criar
um novo, armazenar no HashMap e fornecer a
referência dele;
­Shape e Circle: Interface para definir uma
forma gráfica e implementação da mesma
como círculo, que são utilizadas pelo
ShapeFactory e fornecidas ao cliente
FlyweightPatternDemo;

1 2 3 4 5 6 7 8 9 10
Flyweight Implementação

Passo 1: implemente a classe abstrata forma Passo 2: implemente as classes circulo e quadrado
Esta classe abstrata será utilizada para gerar Estas classes são filhas da classe forma
outras formas concretas. package flyweightexemplo;
public class Circulo extends Forma {
public static int num;
public Circulo(){
package flyweightexemplo; num++; }
public abstract class Forma { @Override
String nome; void desenhar(int X, int Y, int novoX, int novoY) {
System.out.println("Nova localizacao do "+this.nome+" eh\nX: "+novoX+", Y: "+novoY+".\n\n");
abstract void desenhar(int X, int Y, int novoX, int novoY); }
} }
package flyweightexemplo;
public class Quadrado extends Forma {
public static int num;
public Quadrado(){
num++; }
@Override
void desenhar(int X, int Y, int novoX, int novoY) {
System.out.println("Nova localizacao do "+this.nome+" eh\nX: "+novoX+", Y: "+novoY+".\n\n");
}
}

1 2 3 4 5 6 7 8 9 10
Flyweight Implementação

Passo 3: implemente a classe FormaFactory Passo 4: implemente a classe FormaClient


package flyweightexemplo; Esta classe utiliza o fabrica de formas para criar
import java.util.HashMap;
import java.util.Map; uma forma e desenha­la
public class FormaFactory {
private static Map<String, Forma> flyweights = new HashMap<>(); package flyweightexemplo;
public static Forma getForma(String chave) { public class FormaClient {
if(flyweights.containsKey(chave)) { private Forma forma;
return flyweights.get(chave); }
Forma forma; public FormaClient(String nome) {
forma = FormaFactory.getForma(nome);
switch(chave) { }
case "Circulo": private int X = 0;
forma = new Circulo(); private int Y = 0;
forma.nome = "Circulo"; break;
case "Quadrado": public void desenharNovaPosicao(int novoX, int novoY) {
forma = new Quadrado(); forma.desenhar(X, Y, novoX, novoY);
forma.nome = "Quadrado"; break; X = novoX;
default: throw new IllegalArgumentException("Tipo nao suportado."); Y = novoY;
} }
}
flyweights.put(chave, forma);
return forma;
}
}

1 2 3 4 5 6 7 8 9 10
Flyweight Implementação

Passo 5: implemente a classe executora

package flyweightexemplo;
public class FormaTeste {
public static void main(String[] args) throws Exception {
FormaClient formas[] = {
new FormaClient("Circulo"),
new FormaClient("Circulo"),
new FormaClient("Quadrado"),
new FormaClient("Quadrado"),
};
formas[0].desenharNovaPosicao(20, 30);
formas[1 ].desenharNovaPosicao(30, 40);
formas[2].desenharNovaPosicao(1 , 2);
formas[3].desenharNovaPosicao(2, 4);
System.out.println("Instancias de Circulo: "+Circulo.num);
System.out.println("Instancias de Quadrado: "+Quadrado.num);
}
}

1 2 3 4 5 6 7 8 9 10
Proxy Caso de Uso e
Diagrama Conceitual

O Proxy é um padrão de projeto estrutural que permite


que você forneça um substituto para outro objeto.
Um proxy controla o acesso ao objeto original,
permitindo que você faça algo antes ou depois do
pedido chegar ao objeto original.
Podemos criar este padrão quando:
­ temos um objeto caro para ser criado e não
queremos permitir acesso direto a esse objeto.
­ restringimos o acesso a partes da sua aplicação.
­ podemos ter uma ligação entre o sistema e um sistema
remoto.
­ queremos fazer cache de chamadas já realizadas.
­ queremos interceptar quaisquer chamadas de
métodos no objeto real (por exemplo, criar logs).

1 2 3 4 5 6 7 8 9 10
Proxy Implementação

Passo 1: implemente a interface ObjetoCaro Passo 2: implemente a classe ImplementacaoObjetoCaro


Esta interface contem todos os métodos, ainda sem Esta classe contrata a interface ObjetoCaro, o que
a implementação do padrão. obriga a classe Implementacao ObjetoCaro a
implementar as ações.

package proxy; package proxy;


public interface ObjetoCaro public class ImplementacaoObjetoCaro implements ObjetoCaro {
{
void process(); public ImplementacaoObjetoCaro() {
} heavyInitialConfiguration();
}
@Override
public void process() {
System.out.println("Processamento Completo :)");
}
private void heavyInitialConfiguration() {
System.out.println("Carregando a configuração inicial :)");
}
}

1 2 3 4 5 6 7 8 9 10
Proxy Implementação

Passo 3: implemente a classe ProxyObjetoCaro Passo 4: implemente a classe Proxy


Esta classe contrata a interface ObjetoCaro, o que Esta classe Proxy executa a classe Proxy, em vez de
obriga a classe ProxyObjetoCaro a implementar as acessar o ObjetoCaro
ações.

package proxy; package proxy;


public class ProxyObjetoCaro implements ObjetoCaro { public class Proxy {
private static ObjetoCaro object; public static void main(String[] args) {
@Override ObjetoCaro object = new ProxyObjetoCaro();
public void process() { object.process();
if (object == null) { object.process();
object = new ImplementacaoObjetoCaro(); }
}
object.process(); }
}
}

1 2 3 4 5 6 7 8 9 10
Chain of responsability Caso de Uso

Chain of Responsability é um padrão de projeto comportamental que utiliza a ideia de baixo acoplamento
por permitir que outros objetos da cadeia tenham a oportunidade de tratar uma solicitação. Consiste em uma
série de objetos receptores e de objetos de solicitação.
Cada objeto de solicitação possui uma lógica interna que separa quais são tipos de objetos receptores que
podem ser manipulados. O restante é passado para o próximo objetos de solicitação da cadeia.
A intenção é evitar o acoplamento do remetente de uma solicitação ao seu receptor, ao dar a oportunidade
de tratar essa solicitação a mais de um objeto. Encadear os objetos receptores, passando a solicitação ao
longo da cadeia até que um objeto a trate. A principal função é evitar a dependência entre um objeto
receptor e um objeto solicitante.

As vantagens deste padrão são:


­ Permite determinar quem será o objeto que irá tratar a requisição durante a execução, e qual a ordem de
tratamento.
­ Cada objeto pode tratar ou passar a mensagem para o próximo na cadeia. Dessa forma, o acoplamento é
reduzido, dando ainda flexibilidade adicional na atribuição de responsabilidades.
­. É possível introduzir novos objetos no sistema sem quebrar o código existente

1 2 3 4 5 6 7 8 9 10
Chain of responsability Diagrama
Conceitual

1 2 3 4 5 6 7 8 9 10
Chain of responsability Implementação

Passo 1: implemente a interface CaixaEletronico Passo 2: implemente as classes CaixaNota10,


CaixaNota20, CaixaNota50 e CaixaNota100
Esta interface contem todos os métodos, ainda sem
a implementação do padrão. Estas classes irão formar a rede de responsabilidade.

package chain;
package chain;
public class CaixaNota1 0 implements CaixaEletronico {
public interface CaixaEletronico { private CaixaEletronico proximoCaixa;
void setProximoCaixa(CaixaEletronico proximoCaixa); @Override
public void setProximoCaixa(CaixaEletronico proximoCaixa) {
void sacar(SaqueDinheiro saque); this.proximoCaixa = proximoCaixa; }
}
@Override
public void sacar(SaqueDinheiro saque) {
if (saque.getValor() >= 1 0) {
int notas = saque.getValor() / 1 0;
int restante = saque.getValor() % 1 0;
System.out.println("Liberando " + notas + " de 1 0 reais");
if (restante != 0)
this.proximoCaixa.sacar(new SaqueDinheiro(restante));
} else {
this.proximoCaixa.sacar(saque);
}
}
}

1 2 3 4 5 6 7 8 9 10
Chain of responsability Implementação

package chain; package chain; package chain;


public class CaixaNota20 implements CaixaEletronico { public class CaixaNota50 implements CaixaEletronico { public class CaixaNota1 00 implements CaixaEletronico {
private CaixaEletronico proximoCaixa; private CaixaEletronico proximoCaixa; private CaixaEletronico proximoCaixa;
@Override @Override @Override
public void setProximoCaixa(CaixaEletronico public void setProximoCaixa(CaixaEletronico public void setProximoCaixa(CaixaEletronico
proximoCaixa) { proximoCaixa) { proximoCaixa) {
this.proximoCaixa = proximoCaixa; this.proximoCaixa = proximoCaixa; this.proximoCaixa = proximoCaixa;
} } }
@Override @Override @Override
public void sacar(SaqueDinheiro saque) { public void sacar(SaqueDinheiro saque) { public void sacar(SaqueDinheiro saque) {
if (saque.getValor() >= 20) { if (saque.getValor() >= 50) { if (saque.getValor() >= 1 00) {
int notas = saque.getValor() / 20; int notas = saque.getValor() / 50; int notas = saque.getValor() / 1 00;
int restante = saque.getValor() % 20; int restante = saque.getValor() % 50; int restante = saque.getValor() % 1 00;
System.out.println("Liberando " + notas + " de 20 System.out.println("Liberando " + notas + " de 50 System.out.println("Liberando " + notas + " de 1 00
reais"); reais"); reais");
if (restante != 0) if (restante != 0) if (restante != 0)
this.proximoCaixa.sacar(new this.proximoCaixa.sacar(new this.proximoCaixa.sacar(new
SaqueDinheiro(restante)); SaqueDinheiro(restante)); SaqueDinheiro(restante));
} else { } else { } else {
this.proximoCaixa.sacar(saque); this.proximoCaixa.sacar(saque); this.proximoCaixa.sacar(saque);
} } }
} } }
} } }

1 2 3 4 5 6 7 8 9 10
Chain of responsability Implementação

package chain;
public class Chain {
Passo 3: implemente a classe SaqueDinheiro private CaixaEletronico caixa1 00;
Esta classe dispara a rede de responsabilidade public Chain() {
this.caixa1 00 = new CaixaNota1 00();
CaixaEletronico caixa50 = new CaixaNota50(); caixa1 00.setProximoCaixa(caixa50);
package chain; CaixaEletronico caixa20 = new CaixaNota20(); caixa50.setProximoCaixa(caixa20);
public class SaqueDinheiro { CaixaEletronico caixa1 0 = new CaixaNota1 0(); caixa20.setProximoCaixa(caixa1 0); }
private int valor; public static void main(String[] args) {
public SaqueDinheiro(int valor) { Chain caixas = new Chain();
this.valor = valor; int valor1 = 240;
} System.out.println("\nSAQUE DE " + valor1 );
public int getValor() { SaqueDinheiro saque1 = new SaqueDinheiro(valor1 );
return this.valor; caixas.caixa1 00.sacar(saque1 );
} int valor2 = 30;
}
System.out.println("\nSAQUE DE " + valor2);
SaqueDinheiro saque2 = new SaqueDinheiro(valor2);
caixas.caixa1 00.sacar(saque2);
Passo 4: implemente a classe chain e a int valor3 = 770;
executora System.out.println("\nSAQUE DE " + valor3);
SaqueDinheiro saque3 = new SaqueDinheiro(valor3);
A classe CHain implementa a rede de caixas.caixa1 00.sacar(saque3);
}
responsabilidade e a classe main executa todo }
o código.
1 2 3 4 5 6 7 8 9 10
Command Caso de Uso

O principal objetivo deste padrão é encapsular uma solicitação como um objeto, fazendo com que
permita criar parâmetros em outros objetos com diferentes solicitações, além disso é possível: enfileirar
ou registrar solicitações e implementar recursos de cancelamento de operações. Isso inclui informações
como método que pertence ao objeto e até os valores de parâmetros.
As vezes temos uma série de eventos sendo recebidos ou é preciso atualizar uma interface de usuário
operando diferentes classes para uma ação. Usando esse método, podemos separar essa lógica em
classes de responsabilidade única por ação, podendo ter um histórico de execução ou permitindo
desfazer uma ação caso algo esteja errado.
O ponto principal do Command é o uso de uma classe abstrata ou interface que inclui uma operação
abstrata “Execute”. As subclasses concretas do Command especificam um par receptor­ação através
do armazenamento do receptor como uma variável de instância e pela implementação de Execute
para invocar a solicitação. Desta forma, todos os clientes de objetos command tratam cada objeto
como uma “caixa preta”, simplesmente invocando o método execute(). O Command faz com que seja
mais fácil construir componentes que transmitem, enfileiram ou executam métodos em um momento de sua
escolha, sem a necessidade de conhecer a classe do método ou os parâmetros do método.

1 2 3 4 5 6 7 8 9 10
Command Diagrama
Conceitual

CarroMoverCMD

ControleRemoto <<interface>>
ComandoBase Carro

executar
botaoLigarPress
botaoDesligarPress
CarroMoverCMD mover
parar

1 2 3 4 5 6 7 8 9 10
Command Implementação

Passo 1: implemente as classes pião e carro Passo 2: implemente a interface ComandoBase


Estas duas classes reproduzem objetos que são Esta interface vai ser contrada por todos os
controlados por um controle remoto. comandos executados pelo controle remoto.

package receivers; package comandos;


public class Piao { public interface ComandoBase {
public void rodarPiao() { System.out.println("Piao comecou a rodar"); }
void executar();
public void pararPiao() { System.out.println("Piao parou de rodar"); } }
}

package receivers;
public class Carro {
public void mover() { System.out.println("Carro está movendo"); }
public void parar() { System.out.println("Carro foi parado"); }
}

1 2 3 4 5 6 7 8 9 10
Command Implementação

Passo 3: implemente a classe PiaoRodarComando Passo 4: implemente a classe CarroMoverComando


Esta classe implementa o comando de rodar o pião, Esta classe implementa o comando de mover o
contratando a interface ComandoBase. carro, contratando a interface ComandoBase.

package comandos; package comandos;


import receivers.Piao; import receivers.Carro;
public class PiaoRodarComando implements ComandoBase{ public class CarroMoverComando implements ComandoBase {
private Piao piao; private Carro carro;
public PiaoRodarComando (Piao piao) { public CarroMoverComando(Carro carro) {
this.piao = piao; this.carro = carro;
} }
@Override @Override
public void executar() { public void executar() {
System.out.println("PiaoRodarComando.executar(): Invocando System.out.println("CarroMoveComando.executar(): Invocando
rodarPiao() no Piao"); mover() no Carro");
piao.rodarPiao(); carro.mover();
} }
} }

1 2 3 4 5 6 7 8 9 10
Command Implementação

Passo 5: implemente a classe PiaoPararComando Passo 6: implemente a classe CarroPararComando


Esta classe implementa o comando de parar o pião, Esta classe implementa o comando de parar o
contratando a interface ComandoBase. carro, contratando a interface ComandoBase.

package comandos; package comandos;


import receivers.Piao; import receivers.Carro;
public class PiaoPararComando implements ComandoBase{ public class CarroPararComando implements ComandoBase{
private Piao piao; private Carro carro;
public PiaoPararComando (Piao piao) { public CarroPararComando(Carro carro) {
this.piao = piao; this.carro = carro;
} }
@Override @Override
public void executar() { public void executar() {
System.out.println("CarroPararComando.executar(): Invocando parar()
System.out.println("PiaoPararComando.executar(): Invocando no Carro");
pararPiao() no Piao");
carro.parar();
piao.pararPiao(); }
}
} }

1 2 3 4 5 6 7 8 9 10
Command Implementação

Passo 7: implemente a classe Controle Remoto Passo 8: implemente a classe executora


Estas duas classes reproduzem objetos que são package invoker;
controlados por um controle remoto. import comandos.*;
import receivers.*;
public class ControleRemotoTeste {
package invoker; public static void main(String[] args) {
ControleRemoto controleRemoto = new ControleRemoto();
import comandos.ComandoBase; System.out.println("----------Testando botaoLigar para Carro----------");
Carro carro = new Carro();
public class ControleRemoto { ComandoBase carroMoverComando = new CarroMoverComando(carro);
ComandoBase ligar,desligar; controleRemoto.botaoLigarPressionado(carroMoverComando);
public void botaoLigarPressionado(ComandoBase botaoLigar) { System.out.println("\n---------Testando botaoDesligar para Carro--------");
this.ligar = botaoLigar; ComandoBase carroPararComando = new CarroPararComando(carro);
ligar.executar(); controleRemoto.botaoDesligarPressionado(carroPararComando);
} System.out.println("\n-----------Testando botaoLigar para Piao----------");
public void botaoDesligarPressionado(ComandoBase botaoDesligar) { Piao piao = new Piao();
this.desligar = botaoDesligar; ComandoBase piaoRodarComando = new PiaoRodarComando(piao);
desligar.executar(); controleRemoto.botaoLigarPressionado(piaoRodarComando);
} System.out.println("\n---------Testando botaoDesligar para Piao---------");
} ComandoBase piaoPararComando = new PiaoPararComando(piao);
controleRemoto.botaoDesligarPressionado(piaoPararComando);
}
}

1 2 3 4 5 6 7 8 9 10
Iterator Caso de Uso

É um padrão que provem uma forma de sequencialmente acessar os elementos de uma coleção sem
expor sua representação interna.
Pode ser usado quando:
­ Quando necessário remover a complexidade de dentro da coleção principal. Isso permite que a
coleção foque apenas em armazenar dados de maneira eficiente.
­ Sua coleção pode ter vários modos de travessia.
­ Quando quer disponibilizar protocolos de travessia para diferentes tipos de coleções.
­ Para acessar o conteúdo de uma coleção sem expor suas representação interna.
As principais vantagens de utilizar o padrão Iterator são: você pode atrasar uma iteração e continuá
la quando necessário; é possível atravessar várias vezes a mesma coleção em paralelo usando outro
objeto iterator; não polui o código do objeto principal com vários métodos e algoritmos de travessia
diferentes; é fácil adicionar novos objetos iteradores com algoritmos de travessia completamente
diferentes.

1 2 3 4 5 6 7 8 9 10
Iterator Diagrama
Conceitual

1 2 3 4 5 6 7 8 9 10
Iterator Implementação

Passo 1: implemente uma lista sem usar Iterator Passo 2: implemente uma lista usando Iterator
package iteratorexemplo; package iteratorexemplo;
import java.util.Iterator; import java.util.Iterator;
import java.util.ArrayList; import java.util.ArrayList;
public class IteratorExemplo {
public class IteratorExemplo {
public static void main(String[] args) {
public static void main(String[] args) {
//Faz a coleção
ArrayList<String> cars = new ArrayList<String>(); ArrayList<Integer> numbers = new ArrayList<Integer>();
cars.add("Fiat"); numbers.add(1 2); numbers.add(8);
cars.add("BMW"); numbers.add(2); numbers.add(23);
cars.add("Ford");
cars.add("Tesla"); System.out.println(numbers);
//Pega o iterator //Pega o iterator
Iterator<String> it = cars.iterator(); Iterator<Integer> it2 = numbers.iterator();
//Mostra o primeiro item //Pega o e remove um item se for menor que 1 0
System.out.println("-------- Mostra o primeiro item --------"); while(it2.hasNext()) {
System.out.println(it.next()); Integer i = it2.next();
if(i < 1 0) {
//Percorre o Array it2.remove();
System.out.println("-------- Percorre o Array --------"); }
while(it.hasNext()) { }
System.out.println(it.next()); System.out.println(numbers);
} }
} }
}

1 2 3 4 5 6 7 8 9 10
Mediator Caso de Uso

É um padrão de projeto comportamental usado frequentemente quando se deseja encapsular a forma


como os objetos interagem entre si. Promove o fraco acoplamento entre os componentes fazendo­os se
comunicar indiretamente, por meio de um objeto mediador especial.
Evita que objetos se refiram uns aos outros explicitamente. Facilita a modificação, extensão e
reutilização de componentes porque eles não serão mais dependentes de diversas outras classes.
Pode ser usado quando:
­ Quando você precisa de um conjunto de objetos se comunicam de maneira bem definida, porém
complexas, o que dificulta o entendimento.
­ Quando um objeto é difícil de ser reutilizado pois se referencia/comunica com muitos outros objetos.
­ Quando um comportamento está distribuído entre diversas classes que deveria ser customizável,
evitando a especialização em subclasses.

1 2 3 4 5 6 7 8 9 10
Mediator Diagrama
Conceitual

Torre de comando do aeroporto


Considere dois pilotos de avião,
um está aterrissando e outro está
decolando, eles se comunicam de
forma direta? A resposta é não.
As mensagens são todas
controladas pela torre de controle,
que possuí a responsabilidade de
gerenciar quem decola e quem
aterrissa. As restrições de decolagem
e aterrissagem ficam por conta da torre de controle.
Observe que neste exemplo têm­se os participantes do padrão. O MediatorConcreto é a torre de controle e
como ColegaConcreto os pilotos de avião.
É importante ressaltar que a torre de controle não controla o voo por completo.

1 2 3 4 5 6 7 8 9 10
Mediator Implementação

Pesquisa a ser realizada pelos alunos.

1 2 3 4 5 6 7 8 9 10
Memento Caso de Uso

É um padrão de projeto comportamental que permite que o usuário salve e restaure o estado anterior
de um objeto sem revelar os detalhes e os dados de sua implementação.
Pode ser usado em aplicações que precisem recuperar os dados anteriores de um objeto específico,
por exemplo na personalização de relatórios, possibilitando que o usuário desfaça as alterações.
Ao implementar o “desfazer” existe a possibilidade de usar em conjunto o Command e o Memento, por
exemplo o objeto será salvo momentos antes do usuário executar um comando.

1 2 3 4 5 6 7 8 9 10
Memento Diagrama
Conceitual

Editor de Texto
Será utilizado como exemplo um editor de texto
que permite com que o usuário crie modificações
que podem ser desfeitas ou repetidas.
O “desfazer” é baseado na colaboração entre
os padrões Memento e Command. O editor rastreia
um histórico dos comandos executados. Antes de
executar qualquer comando, ele faz um backup e
o conecta ao objeto de comando. Após a execução,
ele adiciona o comando executado para o histórico.
Quando um usuário solicita o desfazer, o editor busca um comando recente do histórico e restaura o estado do
backup mantido dentro desse comando. Se o usuário solicitar outro desfazer, o editor utilizará o próximo
comando do histórico e assim por diante.
Os comandos revertidos são mantidos no histórico até que o usuário faça algumas modificações nas formas na
tela. Isso é crucial para refazer comandos desfeitos.

1 2 3 4 5 6 7 8 9 10
Memento Implementação

Pesquisa a ser realizada pelos alunos.

1 2 3 4 5 6 7 8 9 10
Observer Caso de Uso

O Observer é um padrão de projeto comportamental que permite que você defina um mecanismo de
assinatura para notificar múltiplos objetos sobre quaisquer eventos que aconteçam com o objeto que
eles estão observando.
Facilita a comunicação entre objetos em tempo de execução e podemos introduzir novas classes
assinantes sem ter que mudar o código da publicadora.
Pode ser usado quando:
­ Quando uma modificação do estado de um objeto implica modificações em outros objetos;
­ Utilize o padrão quando alguns objetos em sua aplicação devem observar outros, mas apenas por
um tempo limitado ou em casos específicos.
­ Quando uma mudança a um objeto requer mudanças a outros e você não sabe quantos outros
objetos devem mudar.
­ Quando um objeto deve ser capaz de avisar outros sem fazer suposições sobre quem são os objetos.

1 2 3 4 5 6 7 8 9 10
Observer Diagrama
Conceitual

BinaryObserver

HexaObserver Observer Subject

update mover
parar

OctalObserver

1 2 3 4 5 6 7 8 9 10
Observer Implementação

Passo 1: implemente a Passo 2: implemente as classes concretas binaryObserver, hexaObserver e octalObserver


classe abstrata
observer public class BinaryObserver extends Observer { public class HexaObserver extends Observer { public class OctalObserver extends Observer {
public BinaryObserver(Subject subject) { public HexaObserver(Subject subject){ public OctalObserver(Subject subject) {
public abstract class Observer { this.subject = subject; this.subject = subject; this.subject = subject;
this.subject.attach(this); this.subject.attach(this); this.subject.attach(this);
protected Subject subject; } } }
public abstract void update(); @Override @Override @Override
} public void update() { public void update() { public void update() {
System.out.println( "Código binário é: " + System.out.println( "Código hexadecimal System.out.println( "Código octal é: " +
Integer.toBinaryString( subject.getState() ) ); é: " + Integer.toHexString( subject.getState() ) Integer.toOctalString( subject.getState() ) );
}
} } }
} }

1 2 3 4 5 6 7 8 9 10
Observer Implementação

Passo 3: implemente a classe subject Passo 4: implemente o executor

import java.util.ArrayList; public class ObserverPatternDemo {


import java.util.List;
public static void main(String[] args) {
public class Subject {
Subject subject = new Subject();
private List<Observer> observers = new ArrayList<Observer>();
private int state; new HexaObserver(subject);
new OctalObserver(subject);
public int getState() { new BinaryObserver(subject);
return state;
} System.out.println("Primeiro estado é: 1 5");
subject.setState(1 5);
public void setState(int state) {
this.state = state; System.out.println("\n\n\n");
notifyAllObservers();
} System.out.println("Segundo estado é: 1 0");
subject.setState(1 0);
public void attach(Observer observer) { }
observers.add(observer); }
}
public void notifyAllObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}

1 2 3 4 5 6 7 8 9 10
State Caso de Uso

É um padrão de projeto comportamental que permite que um objeto altere seu comportamento quando
seu estado interno muda. O padrão encapsula os estados em classes separadas e delega as tarefas
para o objeto que representa o estado atual. Os comportamentos mudam com o estado interno.
Ele extrai comportamentos relacionados ao estado em classes separadas de estado, e força o objeto
original a delegar o trabalho para uma instância dessas classes, em vez de agir por conta própria.
Pode ser usado quando:
­ Quando temos um objeto que se comporta de maneira diferente dependendo do seu estado atual,
quando o número de estados é enorme, e quando o código estado específico muda com frequência.
­ Para simplificar os casos em que há código complicado e extenso de decisão que depende do
estado do objeto.
­ Quando você tem muito código duplicado em muitos estados parecidos e transições de uma
máquina de estado baseada em condições.

1 2 3 4 5 6 7 8 9 10
State Diagrama
Conceitual

1 2 3 4 5 6 7 8 9 10
State Implementação

Passo 1: implemente a classe abstrata EstadoLivro Passo 2: implemente a classe Disponível

package state; package state;


/** Esta é a classe abstrata que define as operaçõe específicas do Estado. /** Um dos estados concretos do livro. A classe Disponivel faz a
* Os métodos podem ser declarados abstratos, de modo que as classes * transição Disponivel -> Emprestado ao chamar o método solicitar.
* derivadas sejam forçadas a implementá-los, ou podem ter uma * Ignora as devoluções (não se contemplam várias cópias do mesmo livro) */
* implementação por padrão */
public class Disponivel extends EstadoLivro {
public abstract class EstadoLivro {
// Uma vez que neste exemplo os estados dos livros não vão conter
// Os métodos devolver e solicitar são abstratos (devem ser implementados // atributos dependentes do contexto, fazemos com que Disponivel seja
// pelos estados concretos) e são tomados como argumento livro // um Singleton
public abstract void devolver(Livro livro); private static Disponivel instancia; // Instãncia do Singleton Disponivel
public abstract boolean solicitar(Livro livro);
protected Disponivel() {}
// Além disso, adicionamos um método com um String que identifica o estado
// do livro -- a definição estabelece um valor por padrão que será usado se as public static Disponivel instancia() {
// subclasses não o redefinirem. if (instancia == null) {
instancia = new Disponivel();
public String toString() { }
return "Desconhecido";
} return instancia;
} }

1 2 3 4 5 6 7 8 9 10
State Implementação

Passo 3: implemente a classe Emprestado

// Métodos específicos deste estado concreto. solicitar modifica o estado package state;
// do livro, enquanto que devolver simplesmente o ignora.
/** Um dos estados concretos do livro. A classe Emprestado faz a
public boolean solicitar(Livro livro) { * transição Emprestado -> Disponivel ao chamar o método devolver.
* Ignora os pedidos (não se contemplam reservas). */
System.out.println("Solicitando o livro " + livro);
livro.estabelecerEstado(Emprestado.instancia()); public class Emprestado extends EstadoLivro {
return true;
} // Dado que neste exemplo os estados dos livros não vão conter
// atributos dependentes do contexto, fazemos com que Emprestado
public void devolver(Livro livro) { // seja um Singleton.
System.out.println("O livro " + livro + " já está disponível"); private static Emprestado instancia; // Instância do Singleton Emprestado
}
protected Emprestado() {}
// Redefine o nome do estado...
public String toString() { public static Emprestado instancia() {
if (instancia == null) {
return "Disponivel"; instancia = new Emprestado();
} }
} return instancia;
}

1 2 3 4 5 6 7 8 9 10
State Implementação

Passo 4: implemente a classe Livro

// Métodos específicos deste estado concreto. Devolver faz a transição package state;
// para Disponivel, enquanto que solicitar rejeita.
/** Um Livro pode estar em dois estados: DisponÃvel ou Emprestado, de modo
public boolean solicitar(Livro livro) { * que se escolhermos por representar o estado com um atributo, os
* métodos da classe Livro acabariam por converter-se em condicionais sobre
System.out.println("O livro " + livro + " não está disponível"); * esse estado. */
return false;
} public class Livro {
public void devolver(Livro livro) { private EstadoLivro estado; // implementa associação com o estado
System.out.println("O livro " + livro + " foi devolvido"); private String titulo;
livro.estabelecerEstado(Disponivel.instancia());
} // O construtor da classe, além de inicializar o título do
// livro, define o estado inicial (Disponível). Como neste caso
// Redefine o nome do estado // os estados de livros têm o seu próprio estado, usamos um Singleton.
public String toString() { public Livro(String titulo) {
return "Emprestado"; this.titulo = titulo;
} this.estado = Disponivel.instancia();
}
}
public String toString() {
return (this.titulo + " (" + this.estado + ")" );
}

1 2 3 4 5 6 7 8 9 10
State Implementação

Passo 5: implemente a classe executora

// Este método modifica o estado do livro. Problema: o método deve package state;
// ser acessado a partir de uma classe externa (EstadoLivro), o que exclui
// a visibilidade private e protected. public é demasiado geral pois todas public class State {
// as classes podem acessar o método. Neste caso, sugere-se a
// visibilidade de pacote, com Livro e os seus estados no mesmo pacote . public static void main(String[] args) {
void estabelecerEstado(EstadoLivro estado) { Livro l1 = new Livro("Dora aventureira");
System.out.println("Mudando estado de " +this.estado+ " a " + estado); Livro l2 = new Livro("O Hobbit");
this.estado = estado;
} l1 .solicitar(); // Disponível -> Emprestado
System.out.println("");
// Os métodos de dependentes do estado delegam o comportamento
// definido para cada estado. Uma vez que vamos dar aos estados l1 .solicitar(); // O livro não está disponível
// a responsabilidade de realizar as transições, passamos o livro System.out.println("");
// ao estado para que possa, se lhe interessar, chamar estabelecerEstado.
l1 .devolver(); // Emprestado -> Disponível
public void devolver() { System.out.println("");
this.estado.devolver(this);
} l2.devolver(); // O livro já está disponível
}
public boolean solicitar() {
return this.estado.solicitar(this); }
}
}

1 2 3 4 5 6 7 8 9 10
Strategy Caso de Uso

Esse padrão de projeto transforma um conjunto de comportamentos em objetos e os torna


intercambiáveis (conseguem interagir entre eles) dentro do objeto de contexto original.
O padrão Strategy é muito comum no código Java. É muito usado em várias estruturas para fornecer
aos usuários uma maneira de alterar o comportamento de uma classe sem estendê­la. Algumas
bibliotecas possuem o padrão strategy, sendo elas:
­ java.util.comparator: função que compara e impõe uma ordenação total em algumas coleções de
objetos;
­ java.servlet.filter: é usado para interceptar a requisição do cliente ou fazer pré­processamento;

1 2 3 4 5 6 7 8 9 10
Strategy Diagrama
Conceitual

O strategy é usado para implementar os vários métodos de pagamento em uma


loja. Depois de selecionar um produto para comprar, o cliente escolhe uma forma
de pagamento: débito ou crédito.
Esse padrão de projeto não apenas executa o pagamento real, mas também
alteram o comportamento do formulário de pagamento, fornecendo campos
apropriados para registrar os detalhes do pagamento (dependendo da forma
de pagamento que o usuário escolher).
­Context: mantém uma referência para uma das estratégias concretas e se
comunica com esse objeto através da interface da estratégia.
­Strategy(interface): é uma interface comum à todas as estratégias concretas. Ela
declara um método que o contexto usa para executar uma estratégia.
­ConcreteStrategies: implementam diferentes variações de um algoritmo que o
contexto usa.
O contexto chama o método de execução no objeto strategy ligado cada vez
que ele precisa rodar um algoritmo. O contexto não sabe qual tipo de
estratégia ele está trabalhando ou como o algoritmo é executado.
O Client cria um objeto estratégia específico e passa ele para o contexto. O
contexto expõe um setter que permite o cliente mudar a estratégia associada
com contexto durante a execução,

1 2 3 4 5 6 7 8 9 10
Strategy Implementação

Pesquisa a ser realizada pelos alunos.

1 2 3 4 5 6 7 8 9 10
Visitor Caso de Uso

É um padrão de projeto comportamental que permite Representar uma operação a ser executada nos
elementos de uma estrutura de objetos. Visitor permite definir uma nova operação sem mudar as classes
dos elementos sobre os quais opera.
Pode ser usado quando:
­ Precisamos fazer uma operação em todos os elementos de uma estrutura de objetos complexa (por
exemplo, uma árvore de objetos).
­ Muitas operações distintas e não relacionadas devem ser realizadas numa estrutura de objetos e
você quer evitar "poluir" as classes com estas operações
­ As classes que definem a estrutura de objetos raramente muda mas a adição de novas operações é
frequente.

1 2 3 4 5 6 7 8 9 10
Visitor Diagrama
Conceitual

Fruit

<<interface>> <<interface>> CarrinhoDeCompras


Item CarrinhoDe VisitorImpl
ComprasVisitor

inserir(visitor)
Livro visitar(livro)
visitar(fruit)

1 2 3 4 5 6 7 8 9 10
Visitor Implementação

Passo 1: implemente as interfaces Passo 2: implemente a classe concreta


CarrinhoDeComprasVisitor e Item CarrinhoDeComprasVisitorImpl

public interface CarrinhoDeComprasVisitor { public class CarrinhoDeComprasVisitorImpl implements CarrinhoDeComprasVisitor {


double visitar(Livro livro); @Override
double visitar(Fruit fruta); public double visitar(Livro livro) {
}
//Cupom de desconto
double custo = livro.getPreco() - 5;
custo = Math.round(custo*1 00.0)/1 00.0;
System.out.println("Livro: " + livro.getTitulo() + ", Preço = R$" + custo);
return custo;
}
@Override
public double visitar(Fruit fruta) {
public interface Item {
double custo = fruta.getPrecoPorKg() * fruta.getPeso();
public double inserir(CarrinhoDeComprasVisitor visitor); custo = Math.round(custo*1 00.0)/1 00.0;
} System.out.println("Fruta: " + fruta.getNome() + ", Preço = R$" + custo);
return custo;
}
}

1 2 3 4 5 6 7 8 9 10
Visitor Implementação

Passo 3: implemente a classe Fruit Passo 4: implemente a classe Livro

public class Fruit implements Item { public class Livro implements Item {
private String nome; private String titulo;
private double precoPorKg; private double preco;
private double peso;
public Livro(String titulo, double preco) {
public Fruit(String nome, double precoPorKg, double peso) { this.titulo = titulo;
this.nome = nome; this.preco = preco;
this.precoPorKg = precoPorKg; }
this.peso = peso;
} public String getTitulo() { return titulo; }
public double getPreco() { return preco; }
public String getNome() { return nome; }
public double getPrecoPorKg() { return precoPorKg; } @Override
public double getPeso() { return peso; } public double inserir(CarrinhoDeComprasVisitor visitor) {
return visitor.visitar(this);
@Override }
public double inserir(CarrinhoDeComprasVisitor visitor) { }
return visitor.visitar(this);
}
}

1 2 3 4 5 6 7 8 9 10
Visitor Implementação

Passo 5: implemente a classe executora


public class VisitorExemplo {
public static void main(String[] args) {
System.out.println("\n************** Notinha **************\n");
Item[] items = new Item[] {
new Livro("O cemitério", 32.84),
new Livro("O iluminado", 40.32),
new Fruit("Laranja", 8.35, 1 .56),
new Fruit("Tomate", 9.96, 1 .20)
};
double total = calcularPrecoTotal(items);
total = Math.round(total*1 00.0)/1 00.0;
System.out.println("\n-------------------------------------\n");
System.out.println("Preço total = R$" + total);
}
private static double calcularPrecoTotal(Item[] items) {
CarrinhoDeComprasVisitor visitor = new CarrinhoDeComprasVisitorImpl();
double total = 0;
for(Item item : items) {
total += item.inserir(visitor);
}
return total;
}
}

1 2 3 4 5 6 7 8 9 10
Referências
Livro – Padrões de Projeto ­ Erich Gamma, Richard Helm, Ralph Johnson, e John Vlissides
Artigo – Framework: o que é, quais utilizar e como eles funcionam – Site Hostgator
Pesquisa Abstract Factory, Object Adapter, Facade, Chain of Responsability, Memento, State ­ Daniel Borba
Guimães da Costa / Thais Resende Araújo Borges Bonfim
Pesquisa Builder, Bridge, Flyweight, Command, Strategy ­ David Gabriel B. Jorge / Murillo Sampaio Oliveira Antonio
Pesquisa Prototype, Composite, Proxy, Iterator, Obsever, Visitor ­ Otavio Augusto Ribeiro Araujo
Pesquisa Singleton. Proxy, Iterator, Obsever, Visitor ­ Victor Barcelos Pires de Sousa

Krita Inkscape Scribus Pexels Gimp Synfig Audacity Kdenlive

1 2 3 4 5 6 7 8 9 10
Só mais uma coisa...

@laertecoutinho1

O professor não é dono do saber.


O professor é um organizador de conhecimento, que tem a experiência adequada
para selecionar o que é relevante neste mar infinito de informação.
marco@iftm.edu.br

@marcomacielpro Produzido em 2022

Você também pode gostar