Escolar Documentos
Profissional Documentos
Cultura Documentos
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
1 2 3 4 5 6 7 8 9 10
Padrões Gang of Four História
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
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.
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
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.
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 fastfood 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, observase:
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 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.
1 2 3 4 5 6 7 8 9 10
Builder Implementação
Passo 3: implemente a classe construtora CasaMadeiraBuilder
1 2 3 4 5 6 7 8 9 10
Builder Implementação
Passo 4: implemente a classe construtora CasaConcretoBuilder
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.
1 2 3 4 5 6 7 8 9 10
Object Adapter Diagrama
Conceitual
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.
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.
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.
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
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
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
1 2 3 4 5 6 7 8 9 10
Composite Implementação
1 2 3 4 5 6 7 8 9 10
Composite Implementação
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
1 2 3 4 5 6 7 8 9 10
Decorator Diagrama
Conceitual
1 2 3 4 5 6 7 8 9 10
Decorator Implementação
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ódigofonte 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
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
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
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
1 2 3 4 5 6 7 8 9 10
Flyweight Implementação
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
1 2 3 4 5 6 7 8 9 10
Proxy Implementação
1 2 3 4 5 6 7 8 9 10
Proxy Implementação
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.
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
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
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 receptoraçã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
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
1 2 3 4 5 6 7 8 9 10
Command Implementação
1 2 3 4 5 6 7 8 9 10
Command Implementação
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
1 2 3 4 5 6 7 8 9 10
Mediator Diagrama
Conceitual
1 2 3 4 5 6 7 8 9 10
Mediator Implementação
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
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
update mover
parar
OctalObserver
1 2 3 4 5 6 7 8 9 10
Observer Implementação
1 2 3 4 5 6 7 8 9 10
Observer Implementação
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
1 2 3 4 5 6 7 8 9 10
State Implementação
// 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
// 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
// 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
1 2 3 4 5 6 7 8 9 10
Strategy Diagrama
Conceitual
1 2 3 4 5 6 7 8 9 10
Strategy Implementação
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
inserir(visitor)
Livro visitar(livro)
visitar(fruit)
1 2 3 4 5 6 7 8 9 10
Visitor Implementação
1 2 3 4 5 6 7 8 9 10
Visitor Implementação
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
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
1 2 3 4 5 6 7 8 9 10
Só mais uma coisa...
@laertecoutinho1