Padrões de Projeto
Padrões de Projeto
Introdução
Introdução
Projetar software é uma tarefa difícil. A maioria dos projetistas é capaz de
compreender conceitos como classes, objetos, interfaces e herança.
O desafio reside em aplicá-los para construir software flexível e reutilizável.
Projetistas novatos tendem a se perder com as muitas opções disponíveis e
a recorrer a técnicas não orientadas a objetos com as quais têm certa
familiaridade.
Projetistas experientes, por sua vez, tendem a fazer bons projetos. Eles
sabem que não se deve resolver todo e qualquer problema partindo de
princípios básicos (classes, objetos, herança, relacionamentos,
agregação,...).
Ao contrário, deve-se buscar reutilizar soluções que funcionaram no
Padrões de Projeto - Cristiano Biancardi
Assim, um padrão é um par nomeado problema/solução, que pode ser
utilizado em novos contextos, com orientações sobre com utilizá-lo em
novas situações.
Padrões são destilações de sabedoria acumulada, fornecendo um
jargão-padrão e nomeando os conceitos que praticantes
experimentados aplicam.
Cada padrão sistematicamente nomeia, explica e avalia um importante
projeto que ocorre repetidamente em sistemas OO.
O objetivo de um design pattern é registrar uma experiência no projeto de
software OO, na forma de um padrão passível de ser efetivamente utilizado por
projetistas.
Um projetista familiarizado com padrões de projeto pode aplicá-los
diretamente a problemas de projeto sem ter que redescobrir abstrações e
os objetos que as capturam.
Em geral, um padrão tem quatro elementos essenciais:
Nome: identificação de uma ou duas palavras, que se possa utilizar
para descrever o problema de projeto, suas soluções e conseqüências.
Problema: descreve quando aplicar o padrão. Explica o problema de
projeto e seu contexto.
Solução: descreve os elementos que compõem o projeto, seus
relacionamentos, responsabilidades e colaborações. Não descreve um
particular projeto concreto ou implementação.
Um padrão provê uma descrição abstrata de um problema de projeto e
como uma organização geral de classes e objetos resolve este problema.
Conseqüências: são os resultados e os comprometimentos feitos ao
Padrões de Projeto - Cristiano Biancardi
A sigla “GoF”
“Gang of Four”
Apelido carinhoso pela qual o quarteto Erich Gamma,
Richard Helm, Ralph Johnson e John Vlissides
Ficou conhecido quando escreveram o livro “Design
Patterns”, no início da década de 90
Neste livro, os quatro dividiram um conjunto de 23
padrões em 3 grupos:
Estruturais: lidam com maneiras de se compor objetos.
Comportamentais: caracterizam formas de interação
entre objetos.
Criacionais: lidam com maneiras de se gerenciar a
Padrões Estruturais
Adapter
Façade
Composite
Bridge
Proxy
Flyweight
Decorator
Padrões de Projeto - Cristiano Biancardi
Adapter
Adapter
Permite que classes com interfaces
incompatíveis possam interagir.
Converte a interface de uma classe em outra
interface, permitindo que classes trabalhem em
conjunto, quando isto não seria possível por
causa da incompatibilidade de interfaces.
Figura 1: Plugue europeu
de três pinos
Figura 2: Tomada
comum de dois pinos
Façade
Façade
Fachada
Provê uma interface unificada para um conjunto de classes em um
subsistema.
Define uma interface de nível mais alto para o subsistema,
tornando-o mais fácil de ser usado.
Facilita o trabalho em subsistemas pois são fornecidas as interfaces
de cada subsistema.
Facilita a utilização do sistema: Cliente só precisa conhecer a fachada.
Promove acoplamento fraco:
Padrões de Projeto - Cristiano Biancardi
Existem circunstâncias onde é necessário
utilizar diversas classes diferentes para
que uma tarefa possa ser completada,
caracterizando uma situação onde uma
classe cliente necessita utilizar objetos de
um conjunto específico de classes
utilitárias que, em conjunto, compõem um
subsistema particular ou que representam
O Facade é um padrão que pode apresentar
infinidades de formas de representá-lo. O que
importa para este padrão é que o Cliente
apenas acesse objetos da classe Facade,
esperando algum resultado vindo dela. A classe
Facade é que terá a responsabilidade de entrar
em contato com as diversas instâncias dentro
deste sistema, efetuar possíveis cálculos vindos
de classes abaixo dela e retornar as respostas
que o cliente pediu.
Padrões de Projeto - Cristiano Biancardi
Implementação:
Implementar um Facade demanda definir um
conjunto de operações reduzidas que permita
ocultar a complexidade inerente à utilização de
várias classes de um subsistema.
Exemplo:
O cliente necessita consultar várias entidades a fim de saber se
têm condições de receber um empréstimo. Para isso,
normalmente, o cliente teria que conhecer toda a complexidade
envolvida com as regras de concessão de empréstimos e
aprende-las, no entanto, nada melhor do que deixar isso a cargo
de quem já está no sistema, no caso o Facade, que irá se
preocupar em colher dados das diferentes classes que podem
decidir sobre a possibilidade do empréstimo e retornará esta
informação pronta para o cliente.
FacadeApp é o cliente que busca informações que podem vir de
vários de subsistemas, Facade é a classe responsável por
acessar os subsistemas e trazer respostas de forma
transparente a quem esteja acessando o Facade. Banco,
Emprestimo, Crédito e Consumidor são classes pertencentes
aos subsistemas.
Composite
Composite
Compor objetos em estruturas de árvore
para representar hierarquias todo-parte.
Permite que clientes trate objetos
individuais e compostos de maneira
uniforme.
Padrões de Projeto - Cristiano Biancardi
Exemplo:
Existem gráficos que são compostos de outros
gráficos;
O programa tem que conhecer cada um deles,
Solução:
A classe abstrata representa tanto gráficos simples quanto compostos.
Programa só precisa conhecer Gráfico.
A agregação permite efetuar a composição em GráficoComposto.
Padrões de Projeto - Cristiano Biancardi
Bridge
Bridge
Desacopla uma abstração de sua
implementação.
Abstração e sua implementação variam
independentemente.
O padrão Bridge é útil quando se tem uma
abstração que tem diferentes implementações.
Exemplo Classico de Brigde: drivers
O projeto separa o desenvolvimento da aplicacao do
desenvolvimento dos drivers que implementam as
operações abstratas das quais as aplicacoes
Padrões de Projeto - Cristiano Biancardi
DrawRect()
DrawText()
Window
DrawText()
DrawRect()
WindowImp
DevDrawText()
DevDrawLine()
IconWindow
DrawBorder()
TransientWindow
DrawCloseBox()
XWindowImp
DevDrawText()
DevDrawLine()
PMWindowImp
DevDrawText()
DevDrawLine()
DrawRect()
XDrawLine()
XDrawString()
imp DevDrawLine()
imp DevDrawLine()
imp DevDrawLine()
imp DevDrawLine()
imp
bridge
Exemplo: usando o padrão Bridge para abstrair
o driver específico de banco de dados.
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Class.forName("com.sybase.jdbc2.jdbc.SybDriver");
Class.forName cria uma instância do driver e regista-o no
Padrões de Projeto - Cristiano Biancardi
Proxy
Proxy
Procurador
É um objeto representante/procurador de
outro objeto para controlar o acesso ao
mesmo.
Contexto:
Um cliente precisa acessar um serviço de um outro componente
em um sistema distribuído.
O acesso direto é tecnicamente possível, mas pode não ser a
melhor opção.
Problema:
O acesso direto pode não ser eficiente em tempo de execução,
ter alto custo e não ser seguro.
Solução:
Utilize um representante no cliente que ofereça o serviço de
forma idêntica e realize pré- e pós-processamento adicionais
para garantir a Qualidade do Serviço.
Padrões de Projeto - Cristiano Biancardi
Objetivo principal:
encapsular um objeto através de um outro objeto que
possui a mesma interface, de forma que o segundo
objeto, conhecido como “Proxy”, controla o acesso ao
primeiro, que é o objeto real.
class BusinessComp
{
public void SaveOrder(Order order) {}
}
class BusinessCompProxy {
BusinessComp subject;
public void SaveOrder(Order order) {
using (TransactionScope scope = new TransactionScope () {
try {
subject.SaveOrder(order);
}
catch (Exception ex) {
LogException(ex);
throw;
}
Padrões de Projeto - Cristiano Biancardi
Flyweight
Flyweight
Peso-Pena
Uso de compartilhamento de objetos
visando melhorar a eficiência.
Padrões de Projeto - Cristiano Biancardi
Exemplo: Pool de Conexões
A maior parte das aplicações desenvolvidas normalmente
acessam banco de dados. Sempre que precisar acessar os
dados no servidor a aplicação o realizará através de um objeto
de conexão.
Para criar esta conexão é preciso informar a string de conexão,
que indica qual servidor e qual banco de dados será
estabelecida a conexão etc.
Em resumo, a string de conexão identifica o fornecedor do
banco de dados, nome da máquina onde a aplicação de banco
de dados está instalada, nome do banco de dados da aplicação,
informações de segurança (usuário, senha, autenticação
integrada etc) e parâmetros de controle do Pool de Conexões,
entre outras.
Imagine que sua aplicação tem uma tela que mostra alguns registros
resultantes de uma consulta.
Já percebeu que existe uma demora até que os dados sejam exibidos?
Boa parte desta demora é porque sua aplicação está criando uma conexão
com banco de dados.
Só que este processo de conexão não é tão simples e tem um custo
alto.
Por que? Porque uma conexão com banco de dados consiste de algumas
tarefas que consomem recursos:
•
uma comunicação física, por exemplo um Socket, precisa ser
estabelecida e para isso é necessário um handshake inicial entre
as máquinas; a string de conexão precisa ser analisada e validada;
a conexão deverá ser autenticada contra o servidor; algumas
verificações para registro numa transação corrente etc.
Como uma aplicação precisa interagir várias vezes com o banco de
dados, dependendo de como esteja sendo utilizada, o desempenho e a
escalabilidade da aplicação podem ser comprometidos.
Padrões de Projeto - Cristiano Biancardi
A maioria das aplicações usam uma ou poucas
configurações de banco de dados diferentes,
pois durante a execução da aplicação várias
conexões idênticas serão abertas e fechadas, o
que poderá impactar a performance da sua
aplicação.
Como resolver isso?
Reutilização das conexões.
O Pool de Conexões é um repositório que mantém
Decorator
Decorator
Decorador
Anexar responsabilidades adicionais a um
objeto dinamicamente.
Decorators oferecem uma alternativa flexível ao
uso de herança para estender uma
funcionalidade.“
Exemplo: um toolkit para a construção de
interfaces gráficas deve permitir adicionar
propriedades como bordas ou barras de
rolagem.
Em Java, o uso mais comum de
decoradores é nos objetos que
representam fluxos de entrada e saída
(I/O streams)
java.io: InputStream, OutputStream, Reader,
Padrões de Projeto - Cristiano Biancardi
Padrões Comportamentais
Caracterizam as maneiras pelas quais classes ou objetos interagem e
distribuem responsabilidades.
Chain of Responsability
Observer
Mediator
Memento
Template Method
State
Strategy
Command
Iterador
Interpreter
Visitor
Chain of Responsability
Chain of Responsability
Cadeia de Responsabilidade
Propósito é fazer com que uma coleção de objeto, em vez
de apenas um, forneça funcionalidade.
Aplicação cliente não tem que saber quais objetos são
responsáveis por qual parte da funcionalidade.
Apresenta uma interface simples
Exemplo:
Corretor ortográfico: conjunto de objetos fazendo a correção de
gramática, ortografia, estilo etc.
Observer
Observer
Observador
Intenção
Definir uma dependência um-para-muitos entre objetos de forma
que quando um objeto muda de estado, todos seus dependentes
são notificados e atualizados automaticamente.
Aplicação
Mudar um objeto causando mudanças em outros objetos, sendo
que não se sabe a priori quantos objetos precisam ser mudados.
Fazer um objeto notificar outros objetos de que seu estado
mudou, sem assumir nada sobre os outros objetos.
Exemplo:
Fundos múltiplos investem em ações, de modo que quando o preço
Mediator
Mediator
Mediador
Intenção:
Definir um objeto que encapsula a forma como um conjunto de objetos interage.
Promove o acoplamento fraco entre os objetos ao evitar que os objetos
explicitamente se refiram uns aos outros, permitindo que se varie
independentemente as interações.
Motivação
Em projetos orientados a objetos, é normal distribuir o comportamento entre
várias classes.
Isso pode resultar numa estrutura com muitas conexões entre os objetos e gera
a necessidade de que cada objeto conheça os demais.
Por exemplo:
Objetos da classe ClienteDoBanco, em geral, interagem com objetos da classe
FundoDeInvestimentosMonetatios. Mas não queremos que a classe
Padrões de Projeto - Cristiano Biancardi
Define um objeto que encapsula a
informação de como um conjunto de
outros objetos interagem entre si.
Promove o acoplamento fraco:
permitindo que você altere a forma de interação
Memento
Memento
Usado para restaurar o estado de um
objeto.
Problema:
É preciso guardar informações sobre um objeto
suficientes para desfazer uma operação
Um memento é um pequeno repositório para
guardar estado dos objetos
Pode-se usar outro objeto, um string, um arquivo.
Memento guarda um snapshot no estado interno
de outro objeto - a Fonte
Um mecanismo de Undo irá requisitar um memento da
fonte quando ele necessitar verificar o estado desse
objeto.
Só a fonte tem permissão para recuperar informações
Padrões de Projeto - Cristiano Biancardi
Exemplo:
Cada vez que um objeto for criado ou movido, o sistema criará um
memento do objeto e o guardará em uma pilha.
Cada vez que o usuário clicar no botão Undo, o código irá recuperar
o memento mais recente e restaurar a simulação ao estado
armazenado no topo da pilha.
public class Fonte {
private Memento memento;
private Object estado;
public Memento criarMemento() {
return new Memento();
}
public void setMemento(Memento m) {
memento = m;
public class Memento {
private Object estado;
Memento() { }
void setEstado(Object estado) {
this.estado = estado;
}
Object getEstado() {
return estado;
Padrões de Projeto - Cristiano Biancardi
Template Method
Template Method
Gabarito
Defini o esqueleto de um algoritmo numa classe,
delegando alguns passos às subclasses.
Permite que as subclasses alterem partes do
algoritmo, sem mudar sua estrutura geral.
Quando usar?
Quando a estrutura fixa de um algoritmo puder ser
definida pela superclasse deixando certas partes para
serem preenchidos por implementações que podem
variar
Padrões de Projeto - Cristiano Biancardi
Padrões de Projeto - Cristiano Biancardi
Outro Exemplo:
O método Arrays.sort (java.util) é um bom
exemplo de Template Method.
Ele recebe como parâmetro um objeto do tipo
Comparator que implementa um método
compare(a, b) e utiliza-o para definir as regras
de ordenação.
Padrões de Projeto - Cristiano Biancardi
State
State
Estado
O estado de um objeto, é uma combinação de
valores atuais de seus atributos.
Em tempo de execução, os valores destes
atributos podem variar de acordo com a
execução dos métodos do próprio objeto, ou via
métodos set.
O padrão é usado para permitir que um objeto
altere o seu comportamento quando o seu
estado muda.
Problema:
Algoritmos muitos grandes para representar as transições de
estado.
Objetivo:
usar objetos para representar estados e polimorfismo para
tornar a execução de tarefas dependentes de estado
transparentes.
Padrões de Projeto - Cristiano Biancardi
Estrutura
Contexto: define a interface de interesse aos clientes e mantém uma
instância de um EstadoConcreto que define o estado atual.
Estado: define uma interface para encapsular o comportamento
associado com um estado particular do contexto.
EstadoConcreto: Implementa um comportamento associado ao estado
Exemplo:
Estados de uma porta.
A porta funciona com um botão que alterna os estados de aberta,
Padrões de Projeto - Cristiano Biancardi
Strategy
Strategy
Estratégia
Definir uma família de algoritmos,
encapsular cada um, e fazê-los
intercambiáveis.
Permite que algoritmos mudem
independentemente entre clientes que os
utilizam.
Problema:
Várias estratégias, escolhidas de acordo com
Padrões de Projeto - Cristiano Biancardi
Idêntico a state na implementação.
Estrutura
Strategy: Define uma interface comum para todos os algoritmos
suportados
ConcreteStrategy: Implementa o algoritmo usando a interface de
Strategy
Context: Defini uma interface que permite a Strategy acessar seus
Command
Command
Encapsular uma requisição como um
objeto, permitindo que os clientes
parametrizem diferentes requisições, filas
ou fazer o registro de log de requisições.
Dar suporte operações que podem ser
Padrões de Projeto - Cristiano Biancardi
Motivação:
As vezes precisamos executar uma operação sem se
preocupar com qual objeto que vai realizá-la ou
simplesmente não conhecemos qual objeto vai receber
a delegação para executar tal operação.
Exemplo 1:
Em uma aplicação Cliente/Servidor geralmente temos o
componente Menu que é composto de vários itens. Cada
item do menu equivale uma operação, como salvar um
arquivo, ler arquivo, apagar arquivo, selecionar a paleta
de cores e etc..
•
Quando selecionamos um item do menu uma operação deve
ser realizada. Esta operação pode ser encapsulada em um
objeto, assim reduziremos o acoplamento entre o objeto menu
e o objeto que executa a operação.
Padrões de Projeto - Cristiano Biancardi
Padrões de Projeto - Cristiano Biancardi
Suporte para desfazer operações:
A operação "execute" do Command, pode armazenar
estados para reverter seus efeitos no próprio
comando.
Basta acrescentar na interface Command uma
operação chamada "Unexecute", que terá a
responsabilidade de desfazer a operação realizada
pelo "execute".
Os comandos realizados podem ser armazenados
Iterador
Iterador
Prover uma maneira de acessar os
elementos de um objeto agregado
,seqüencialmente, sem expor sua
representação interna.
Assim, oferece uma interface uniforme
para atravessar diferentes estruturas
agregadas.
Padrões de Projeto - Cristiano Biancardi
Padrões de Projeto - Cristiano Biancardi
Em Java:
Iterators são implementados nas coleções do
Java. É obtido através do método iterator() de
Collection, que devolve uma instância de
java.util.Iterator.
Padrões de Projeto - Cristiano Biancardi
Interpreter
Interpreter
Interpretador.
Propósito: interpretar expressões escritas em uma
gramática formal.
Eficiência não é um fator crítico.
"Dada uma linguagem, definir uma representação para
sua gramática junto com um interpretador que usa a
representação para interpretar sentenças na linguagem.“
Deve-se utilizar o padrão interpreter sempre que for
possível representar sentenças em árvores sintáticas.
Uso:
Implementação de compiladores
Padrões de Projeto - Cristiano Biancardi
AbstractExpression
Fornece a interface comum a todos os nós da árvore sintática.
TerminalExpression
Implementa a operação de interpretação para os símbolos terminais
NonterminalExpression
Implementa a operação de interpretação para os símbolos
nãoterminais.
A operação de interpretação é chamada recursivamente e a base da
recurssão é um símbolo terminal.
Contexto
contém informação que é global ao interpretador tal como valor das
variáveis para uma instância do problema e resultado das operações
realizadas
Cliente
Padrões de Projeto - Cristiano Biancardi
Exemplo:
Analisando uma expressão algébrica.
Regra Gramatical:
•
expressão = literal | somar | subtrair | expressão
Instância do problema:
•
subtrair(somar(subtrair(x,y),z),a)
•
onde x = 5, y = 2, z = 3 e a = 4
Visitor
Visitor
Visitante
Representar uma operação a ser
realizada sobre os elementos de uma
estrutura de objetos.
Permite definir uma nova operação sem
Padrões de Projeto - Cristiano Biancardi
Exemplo Visitor:
Não foi necessário mudar Grafico,
alterando o nome do método na
Classe: gerarPNG para gerarHTML.
Padrões Criacionais
Singleton
Prototype
Builder
Factory
Abstract Factory
Padrões de Projeto - Cristiano Biancardi
Singleton
Singleton
Intenção:
Garantir que uma classe tenha somente uma
instância e fornecer um ponto global de acesso
à mesma.
Motivação
Em muitas situações é necessário garantir que
algumas classes tenham uma e somente uma
instância.
Exemplo: o gerenciador de arquivos num sistema
deve ser único; escalonadores; gerenciadores de
janelas.
Padrões de Projeto - Cristiano Biancardi
Como assegurar que haja uma única instância?
Uma forma é de não permitir chamadas ao construtor
public class ConexaoDB {
private static ConexaoDB myInstance = null;
private Connection conn = null; private String user; private String password;
private String db; private String port; private static String IP;
private ConexaoDB() {
try {
Class.forName("oracle.jdbc.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:" + user
+ "/" + password + "@" + IP + ":" + port + ":" + db);
} catch (SQLException sqle) {
sqle.printStackTrace();
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
} // try
}
public synchronized static ConexaoDB getInstance() {
if (conn == null) conn = new ConexaoDB();
return conn;
}
public Connection getConection(){
return conn;
}
}
Prototype
Prototype
Protótipo
Tem como objetivo criar objetos
específicos a partir da instância de um
protótipo.
Isso permite criar novos objetos através da
cópia deste protótipo.
Um cliente solicita um protótipo e este clona a
si próprio.
Padrões de Projeto - Cristiano Biancardi
Problema:
Criar um objeto novo, mas aproveitar o estado
Estrutura:
Cliente – solicita a um protótipo que crie
uma cópia de si mesmo, gerando outro
objeto.
Prototype – específica uma interface para
clonar a si próprio.
Concrete Prototype – implementa uma
Prototype em Java
Se o objeto apenas contiver tipos primitivos em
seus campos de dados, é preciso
declarar que a classe implementa Cloneable
sobrepor clone() da seguinte forma:
public Object clone() {
try {
return super.clone();
Padrões de Projeto - Cristiano Biancardi
Se o objeto contiver campos de dados que são
referências a objetos, é preciso fazer cópias
desses objetos também.
public class Circulo implements Cloneable{
private Point origem;
private double raio;
public Object clone() {
try {
Circulo c = (Circulo)super.clone();
c.origem = origem.clone(); // Point deve ser clonável!
return c;
} catch (CloneNotSupportedException e) {return null;}
}
Observação:
O padrão Prototype permite que um cliente crie
novos objetos ao copiar objetos existentes
Uma vantagem de criar objetos deste modo é poder
aproveitar o estado existente de um objeto
Em Java: preciso lembrar que ele só faz cópias
rasas: é preciso copiar também cada objeto membro
e seus campos recursivamente.
Padrões de Projeto - Cristiano Biancardi
Builder
Builder
Separar a construção de um objeto
complexo de sua representação para que
o mesmo processo de construção possa
criar representações diferentes.
Move a lógica de construção para um
objeto fora da classe a ser instanciada.
Razões: reduzir o tamanho de uma classe que
tem muitos métodos e também permitir a
Colaborações
O Cliente cria o objeto Diretor e o configura
com o Builder desejado.
O Diretor notifica o Builder sempre que uma
parte do produto deve ser construída
Builder trata solicitações e acrescenta partes
ao produto
Padrões de Projeto - Cristiano Biancardi
Exemplo:
aplicação que converte o formato
RTF
para uma série de outros
formatos
e que permite a inclusão de suporte para conversão para outros
formatos, sem a alteração do código fonte do leitor de RTF.
A implementação da solução:
realizada através de uma classe de leitura (director) associada a uma
classe capaz de converter o formato RTF para outra representação
(builder).
o objeto da classe de leitura lê cada
token
do texto e executa o método
apropriado no objeto de conversão, de acordo com tipo do token.
a classe de conversão possui um método para cada tipo de token,
incluindo os
caracteres
comuns, parágrafos, fontes e etc.
Para cada formato de texto suportado é criada uma classe de
conversão especializada (concrete builder).
Um conversor para formato
ASCII
, por exemplo, poderia ignorar
qualquer requisição para converter tokens que não fossem
caracteres comuns.
Um conversor para o formato
, por outro lado, iria processar
Padrões de Projeto - Cristiano Biancardi
abstract class ConversorTexto {
public void converterCaractere(char c) {}
public void converterParagrafo() {}
public void converterFonte(Fonte f) {}
}
class ConversorPDF extends ConversorTexto {
public void converterCaractere(char c) {
System.out.print("Caractere PDF");
}
public void converterParagrafo() {
System.out.print("Parágrafo PDF");
}
public void converterFonte(Fonte f) {
System.out.print("Fonte PDF");
}
}
class ConversorTeX extends ConversorTexto {
public void converterCaractere(char c) {
System.out.print("Caractere Tex");
}
public void converterParagrafo() {
System.out.print("Paragrafo Tex");
}
public void converterFonte(Fonte f) {
System.out.print("Fonte Tex");
}
}
class ConversorASCII extends ConversorTexto {
public void converterCaractere(char c) {
System.out.print("Caractere ASCII");
}
class LeitorRTF {
private ConversorTexto conversor;
LeitorRTF(ConversorTexto c) {
this.conversor = c;
}
public void lerRTF() {
List<Token> tokens = obterTokensDoTexto();
for (Token t : tokens) {
if (t.getTipo() == Token.Tipo.CARACTERE) {
conversor.converterCaractere(t.getCaractere());
}
if (t.getTipo() == Token.Tipo.PARAGRAFO) {
conversor.converterParagrafo();
}
if (t.getTipo() == Token.Tipo.FONTE) {
conversor.converterFonte(t.getFonte());
}
}
}
}
public class Cliente {
public static void main(String[] args) {
ConversorTexto conversor;
if (args[0].equals("pdf")) {
conversor = new ConversorPDF();
} else if (args[0].equals("tex")) {
conversor = new ConversorTeX();
} else { conversor = new ConversorASCII(); }
LeitorRTF leitor = new LeitorRTF(conversor);
Factory Method
Factory Method
Define uma interface para criar um objeto mas deixa que
subclasses decidam que classe instanciar.
Permite que uma classe delegue a responsabilidade de
instanciação às subclasses.
Usado:
em casos em que o cliente não consegue antecipar a classe de
objetos que deve criar.
O Factory Method decide com base do ‘contexto’, qual das
subclasses ativar.
Um exemplo simples: leitura de objetos serializados num arquivo.
ou quando uma classe quer que suas subclasses especifiquem
Padrões de Projeto - Cristiano Biancardi
Padrões de Projeto - Cristiano Biancardi
//Esta classe abstrata é a Factory que retorna
//instancia de outras factories.
abstract class DAOFactory {
public abstract UserDAO getUserDAO();
public static DAOFactory getInstance(int whichFactory) {
switch (whichFactory) {
case 1:
return new MySqlUserDAOFactory();
case 2:
return new PostgresUserDAOFactory();
default:
return null;
}
}
}
//Factory para MySql
class MySqlUserDAOFactory extends DAOFactory {
@Override
public UserDAO getUserDAO() {
return new MySqlUserDAO();
}
}
//Factory para Postgres
class PostgresUserDAOFactory extends DAOFactory {
@Override
public UserDAO getUserDAO() {
return new PostgresUserDAO();
}
interface UserDAO {
public void save(Object o);
public void update(Object o);
//outros
}
class MySqlUserDAO implements UserDAO {
public void save(Object o) {}
public void update(Object o) {}
}
class PostgresUserDAO implements UserDAO {
public void save(Object o) {}
public void update(Object o) {}
}
//Vamos ver como chamariamos as nossas classes:
public class DemoFactoryMethod{
public static void main(String[] args) {
DAOFactory daoFactory = DAOFactory.getInstance(1);
// retorna a factory para MySql
UserDAO userDAO = daoFactory.getUserDAO();
userDAO.save(new Object());
DAOFactory daoFactory2 = DAOFactory.getInstance(2);
// retorna a factory para Postgres
01 public class FactoryExample {
02 public static void main( String args[] ) {
03 //parâmetro passado como argumento no console
04 //pega a instância do tipo do carro
05 Carro carro = CarroFactory.getCarro( args[0] );
06 //mostra o valor
07 if( carro != null ) {
08 System.out.println( "Preço: " + carro.getPreco() );
09 }
10 }
11 }
Padrões de Projeto - Cristiano Biancardi
Abstract Factory
Abstract Factory
Intenção: fornecer uma interface para a
criação de famílias de objetos relacionados
ou dependentes sem especificar suas
classes completas
Aplicável a situações nas quais o sistema
deve ser independente de como seus
produtos são criados, compostos ou
representados
o sistema deve ser configurado como um
01 public abstract class Fabricante {
02 protected String name;
03
04 public abstract Carro getCarro( String marca );
05
06 public static Fabricante getInstance( String fabricante ) {
07 if( fabricante == null ) {
08 return null;
09 }
10 else if(fabricante.equals("Chevrolet")) {
11 return new Chevrolet();
12 }
13 else if(fabricante.equals("Volkswagen")) {
14 return new Volkswagen();
15 }
16 else {
17 return null;
18 }
19 }
20 }
22 public class Chevrolet extends Fabricante {
23 public Chevrolet() {
24 name = "Chevrolet";
25 }
27 public Carro getCarro( String marca ) {
28 if( marca == null ) { return null; }
31 else if( marca.equals("Vectra") ) {
32 return new Vectra(); }
34 else if( marca.equals("Omega") ) {
35 return new Omega(); }
Padrões de Projeto - Cristiano Biancardi
01 public class AbstractFactoryExample {
02 public static void main( String args[] ) {
03 //parâmetro passado como argumento no console
04 //pega a instância do fabricante
05 Fabricante fab = Fabricante.getInstance( args[0] );
06 //pega a instância do carro, de acordo com o fabricante
07 Carro carro = fab.getCarro( args[1] );
08 //mostra o valor
09 if( carro != null ) {
10 System.out.println( "Preço: " + carro.getPreco() );
11 }
12 }
13 }
43 public class Volkswagen extends Fabricante {
44 public Volkswagen() {
45 name = "Volkswagen"; }
48 public Carro getCarro( String marca ) {
49 if( marca == null ) {
50 return null; }
52 else if( marca.equals("Gol") ) {
53 return new Gol(); }
55 else if( marca.equals("Golf") ) {
56 return new Golf(); }
58 else { return null; }
61 }
Outros
Outros
MVC
Um dos primeiros padrões identificados na área
de software foi o modelo MVC:
model,
view,
controller
Que foi usado no projeto da interface de
Padrões de Projeto - Cristiano Biancardi
Model: responsável pelo armazenamento e manutenção
dos dados utilizados pela aplicação.
Modelo de classes proveniente da fase de análise
View: é a camada responsável pela interface com o
usuário.
Controller: é a camada responsável pelo tratamento de
eventos e implementação das regras de negócio
normalmente implicam em mudanças nos dados através dos
serviços de model.
um grupo de classes que controla, ou sincroniza, o
Motivação Inicial:
Mesmo modelo com diferentes visões!
Interface texto
Interface Desktop
Interface Web ...
Padrões de Projeto - Cristiano Biancardi
Funcionamento:
A visão
Parte usada para transformar e preparar os dados do
modelo para que possam ser apresentados de alguma
forma (HTML, swing etc).
O controlador retira os dados do modelo e os entrega
para a visão (ou retira dados da interface e alimenta o
modelo).
Esta, por sua vez, alimenta templates com estes dados
para que possam ser apresentados ao usuário.
Além disso, efetua-se algum tratamento do tipo:
•
Verificação de campos obrigatórios
O modelo
Parte que encapsula os dados da aplicação.
Fornecer rotinas para administrar e manipular dados.
•
Deve conter métodos para adicionar, eliminar e atualizar
informações dos objetos na base de dados.
•
Também deve conter métodos para obter a lista de objetos
existentes.
De modo geral, a técnica de acesso aos dados deve ser
encapsulada no modelo.
•
Desta forma, se uma aplicação for transferida de um sistema que
usa banco de dados para um sistema que usa arquivos texto para
guardar as informações, o único elemento que precisa ser alterado
será o modelo
Padrões de Projeto - Cristiano Biancardi
O controlador
Responsável pelas respostas às ações dos usuários.
No caso de uma aplicação desktop, uma ação de usuário
(geralmente) é a solicitação de uma consulta aos dados
de um cliente.
O controlador é acionado pela Visão e vai responder de
acordo, fazendo com que o Modelo manipule os dados
necessários (consulta o cliente no banco e monta o objeto
que o representa) para depois passá-los para a Visão
para que possam ser mostrados.
Representa a implementação dos casos de uso: fluxo
Por que o controlador é necessário?
•
Porque se a sua visão mudar, o impacto na aplicação
é pequeno.
•
O controlador diria o seguinte:
"Não me importa como o usuário vê o sistema,
coloque os dados em mim, e sinalizo ao modelo
que eu tenho novas informações para o
Padrões de Projeto - Cristiano Biancardi
Estrutura
Modelo
Visão
Controle
Comando/ações dos usuários
Invoca os métodos públicos
Invoca os métodos públicos para
pesquisa o estado do modelo
Estimula o sistema
Padrões de Projeto - Cristiano Biancardi
Vantagens
O mesmo modelo pode ser usado com diferentes visões (ou aplicações
diferentes).
Clareza e modularidade de projeto.
É possível ter desenvolvimento em paralelo para o modelo, visão e controle
pois são independentes.
Necessário apenas a definição da interface contratual a ser usada.
É muito simples incluir novos clientes apenas incluindo seus visões e
controles.
Desvantagens
Complexidade adicional, só justificável em aplicações de médio e grande
porte.
Não é aconselhável para pequenas aplicações.
Requer uma quantidade maior de tempo para analisar e modelar o sistema.
Requer pessoal especializado.
Padrões de Projeto - Cristiano Biancardi
Simulando uma consulta de cliente:
No formulário (visão), o campo código preenchidos e
validado.
No evento do clique do botão consultar, as informações do
formulário são passadas para um objeto (controlador), que
servirá de meio de transporte para os dados.
Nesse mesmo objeto controlador o modelo é manipulado e o
código é consultado no banco de dados.
Um objeto do tipo cliente é retornado pelo modelo ao
controlador que por sua vez repassa para a visão para que
os dados possam ser mostrados ou uma mensagem de
código não cadastrado seja exibida.
//Isso está no evento do clique do botão cadastrar
//verifica se código é valido
Cliente cli = Controlador. consCliente(tfdcod.getText());
if (cli != null) {
//td ocorreu bem
//Mostra os dados do cliente na tela
} else {
//algo deu errado
//Mostra uma mensagem de erro
}
public Cliente consCliente(String cod ) {
//Aqui o modelo é acessado
return Cliente.consulta();
}
class Cliente {
static Cliente consulta (String cod){
//consulta dados no banco
//se ok retorna o objeto;
Visão
Controle
Padrões de Projeto - Cristiano Biancardi