Análise e Projeto de Sistemas
Padrões de Projeto Introdução
Sérgio Soares sergio@dsc.upe.br
Motivação
O simples uso da orientação a objetos não garante sistemas extensíveis e
reutilizáveis
• Complicações de orientação a objetos (novo paradigma)
É difícil compartilhar a experiência entre experts e novatos
Motivação
Reusabilidade real não se obtém
diretamente de técnicas de “copiar e colar”
• Simples reaproveitamento de módulos de software não resolve
Software é uma forma de
armazenamento de inteligência
• Implementação sintetiza o que foi criado durante o projeto
Padrões
Idéia vem da área de arquitetura (1979)
• Christopher Alexander
• The Timeless Way of Building
Christopher Alexander estudou meios de
melhorar o processo de projeto de edifícios e áreas urbanas
Por exemplo
• arcos e colunas são uma estratégia comprovada para construir edificações seguras
• projeto e instalação de portas e janelas seguem um padrão estabelecido
Padrões em software
Transferido para software em um livro clássico: GoF (1994)
• Sistemas OO bem estruturados têm
padrões recorrentes de classes e objetos Padrões de projeto
• Descrevem e justificam soluções para
problemas de projeto orientado a objetos
• Devem ter sido previamente experimentados e testados
Histórico de padrões de
projeto
1987 – Cunnigham e Beck usaram as idéia de Alexander com Smalltalk
1990 – A GoF (Gamma, Helm, Johnson e Vlissides) iniciou a compilação de um
catálogo
1991 – Pattern Workshop na OOSPLA (Bruce Anderson)
1994 – Primeira conferência em PLoP
Gang of Four (GoF)
E. Gamma and R. Helm and R.
Johnson and J. Vlissides.
Design Patterns -
Elements of Reusable Object-Oriented
Software. Addison-Wesley,
Padrões de Projeto (Design
patterns)
Capturam a experiência de projeto OO São soluções comprovadas para
construir software orientado por objetos flexível e mais extensível
Cada padrão fornece uma solução para um problema comum no projeto de
Vocabulário comum
Passamos a ter um vocabulário comum para
conversar sobre projetos de software
• Soluções que não tinham nome passam a ter nome
• Diferencial de mercado
Em vez de discutir em termos de classes,
atributos, árvores, listas ligadas, passamos a falar em um nível mais alto como Fábricas, Fachadas, Observador, Estratégia, etc.
A maioria dos autores GoF eram entusiastas
de Smalltalk, principalmente o Ralph Johnson • Acabaram baseando o livro em C++ para aumentar
impacto
Benefícios
Permitem compartilhar experiências bem
sucedidas na resolução de problemas • Catálogos
• Conferências
Reduzem a complexidade do processo de
projeto de software
Aumentam confiabilidade do software via o uso
de soluções comprovadas e experiência acumulada
Aumentam grau de reutilização de software
O Formato de um padrão
Forma de descrever padrões deve ser o mais uniforme possível
Todo padrão inclui
• Nome
• Problema
• Solução
• Conseqüências (prós,contras)
Existem vários tipos de formato, em vários livros
O Formato dos padrões no GoF
Nome (inclui número da página)
• um bom nome é essencial para que o padrão caia na boca do povo
Objetivo / Intenção
Também Conhecido Como (AKA) Motivação
• um cenário mostrando o problema e a necessidade da solução
O Formato dos padrões no GoF
Aplicabilidade• como reconhecer as situações nas quais o padrão é aplicável Estrutura
• uma representação gráfica da estrutura de classes do padrão (usando OMT91) em, as vezes, diagramas de interação (Booch 94)
Participantes
• as classes e objetos que participam e quais são suas responsabilidades
Colaborações
Exemplo
Analisar as seções do arquivo pdf do padrão PDC (Persistent Data
Collections) Disponível em http://www.cin.ufpe.br/~scbs/artigos/ massoni_alves_soares_borba_sugarloafplop2001.pdf ou http://twiki.cin.ufpe.br/twiki/pub/SPG/GenteAreaPublications/ PLOP01_massoni.pdf
Análise e Projeto de Sistemas
Padrões de Projeto GoF
Sérgio Soares sergio@dsc.upe.br
Classificação dos padrões GoF
Classificação feita a partir do objetivo
principal do padrão
Padrões fundamentais
• Aplicação de princípios básicos de orientação a objetos
Padrões de criação (creational))
• Descrevem técnicas para instanciar objetos
Padrões estruturais (structural)
• Permitem organizar classes e objetos em estruturas maiores
Padrões comportamentais (behavioral)
Padrões fundamentais
Usados extensivamente nos outros padrões de projeto
Delegation
Delegation
Problema
A herança pode não funcionar bem
• Número exagerado de subclasses
• Herança múltipla proibida em Java e complexa em outras linguagens
Delegation
Solução
Usar delegação
• Composição de classes
Delegation
Conseqüências
Fácil de fazer composição de comportamentos em tempo de execução
Desvantagem: relacionamento fica menos óbvio de entender
• Devemos também minimizar o número de associações
Interface
Problema
Uso de serviços de uma classe atrelando o cliente a uma classe particular
Mudanças no provedor do serviço afetam o cliente
• Perda de extensibilidade e reusabilidade
EnderecoAmericano ed = new EnderecoAmericano(); ...
System.out.println(“Nome Rua”,ed.getStreet()); EnderecoBrasil ed = new EnderecoBrasil();
Interface
Solução
Cliente usa a classe provedora do serviço
através de uma interface
Interface deve ser realizada (implementada)
Interface
Exemplo
interface IEndereco{..}
class EnderecoAmericano implements IEndereco{..} class EnderecoBrasil implements IEndereco{..}
IEndereco ed = new EnderecoAmericano();
Padrões de criação
Guiam decisões de quando e como criar objetos
Para objetos com criação complexa
• Dinamicamente decidir qual classe instanciar
• Quais serão os objetos delegados
Factory Method
Abstract Factory
Factory Method
Problema
Criação de objetos de uma classe nos faz depender de um classe explícita
• Menção e parâmetros do construtor
//software editor de texto if (opcao.equals(“meuDoc”))
DocumentoGeral dg = new MeuDocumento(nome,data,...); ...
dg.abrir(); dg.salvar(); dg.fechar();
Factory Method
Factory Method
Exemplo da solução Factory factory = ...; ... DocumentoGeral dg = factory.criarDocumento(opcao); ... dg.abrir(); dg.salvar(); dg.fechar();Factory Method
Solução
Definir uma interface para criar um objeto (Criador),
deixando que as subclasses decidam qual instanciar
Modo como instanciar também será decidido em
Abstract Factory
Problema
Criação de objetos concretos de acordo com uma
implementação específica
• Mesma família de objetos, mas implementada de uma forma específica
Polimorfismo resolve o problema em parte
Cliente fica dependente da criação destes objetos
class Motor {
public abstract boolean testar(); }
class MotorRenault extends Motor{ public boolean testar(){
//testa motor renault especifico }
Abstract Factory
Problema
//aplicacao de montadora que usa motores Motor m;
Switch (opcao)
case `r’: m = new MotorRenault();.. case ‘t’: m= new MotorToyota();
..
//polimorfismo – otimo ok = m.testar();
Abstract Factory
Abstract Factory
Exemplo da solução //Montadora Motor m; FabricanteAutomoveis fa = FabricanteAutomoveis.criarFabrica(“toyota”); m = fa.criarMotor(); ok = m.testar(); Factory method! Fábrica abstrata!Abstract Factory
Solução
Coordenar a criação de famílias de objetos
Regras de instanciação dos objetos ficam guardadas nas fábricas
Abstract Factory
Consequências
Diminui a dependência entre a aplicação e as subclasses
Para cada tipo de objeto, precisamos ter uma fábrica concreta
Singleton
Problema
Programa precisa garantir que apenas uma instância de uma classe é criada Quando o objeto centraliza o
gerenciamento de serviços
• Como criar uma instância que será global em Java?
• Como fazer clientes capturar a mesma referência da instância única?
Singleton
Solução
Definir uma única instância de uma classe na memória.
• A instância passa a ser global
Quem precisar acessar os serviços da classe vai requisitá-lo ao mesmo objeto
Instancia única de um objeto
public class Gerenciador {
private static Gerenciador instancia;
private Gerenciador() {
... //construcao do objeto }
public static Gerenciador obterInstancia() {
if (instancia == null) {
instancia = new Gerenciador(); }
return instancia; }
Singleton
Consequências
Certeza que existe uma instância apenas de uma classe no sistema
• Segurança implementada de forma encapsulada
Facil acesso a esta instância de todo o programa
Padrões estruturais
Definem como será feita a composição entre classes e seus objetos
Adapter
Iterator
Façade
Bridge
Adapter
Problema
Classes oferecem métodos que não podem ser
utilizados na configuração atual
• Dificulta reuso, principalmente de classes compiladas
Os métodos tem um comportamento correto, mas suas
assinaturas não são desejáveis
• Problemas de nome, tipo de retorno, parâmetros
Adapter
Adapter
Solução
Utilizar uma classe ou mais classes que adaptam a
classe alvo para ser usada
• Clientes da figura e a implementação de círculo ficam totalmente independentes
A classe adaptadora permite separação que traz
Adapter
Consequências
Objetos podem ser reusados através de uma readaptação de suas
interfaces
Cliente não é afetado
Aumento no número de classes e interfaces
Iterator
Problema
Acesso a uma coleção de objetos
Navegação nesta coleção não pode deixar o
cliente dependente da forma de implementação desta coleção
• árvore, tabela hash, grafo . . .
Collection c = new LinkedList(); Object o = c.first();
while (o != null) {
...// processa objeto atual o = o.getNext();
Iterator
Iterator
Solução
Define uma interface que declara métodos para o acesso
seqüencial aos objetos de uma coleção
Uma classe (cliente) que acessa a coleção somente através
de uma interface desse tipo permanece independente da classe que implementa a interface
Iterator
Consequências
Acesso aos objetos da coleção sem
saber da estrutura de armazenamento Podemos usar várias navegações na
mesma coleção (vários iterators) Pode-se criar iterators diferentes
que navegam na coleção de forma diferente
Façade (Fachada)
Problema: classes que necessitam de serviços de várias outras classes
(“subsistemas”)
• Complexidade
Precisamos fornecer uma forma padrão de acesso ao sistema • Simplificar as classes que requisitam serviços
Exemplo: Classes de interface com o usuário pedindo serviços à parte
de negócio de uma banco
Façade (Fachada)
RepositorioContas RepositorioClientes RepositorioAgencias
Façade (Fachada)
Solução
Incluir uma classe Fachada intermediária • Interface única para os serviços do sistema
• Simplifica as classes
• Concentra a inteligência de acesso aos subsistemas em uma classe
Façade (Fachada)
Consequências
Clientes interagem com uma única classe de um pacote.
• A estrutura Fachada está na forma de delegação.
Permite gerenciar arquiteturas de
software envolvendo grandes números de classes.
Bridge
Problema
Abstração acoplada diretamente a uma forma de
Bridge
Problema
Abstração acoplada diretamente a uma forma de
implementação da mesma
O que acontece se mudar
• Novas figuras?
Bridge
Solução
Definir uma interface para todas as
implementações usadas
As abstrações usam (e não herdam) a
Bridge
Consequências
Desacoplamento aumenta a
capacidade de reuso e extensão
Objetos cliente não ficam a par das questões de implementação, nem as abstrações mais importantes
Decorator
Problema
Objeto recebe responsabilidades adicionais
Estender o objeto diretamente pode diminuir a
reusabilidade do mesmo
Criação de hierarquia complexa (difícil de manter)
public class Sistema {
public void fazIsso(){...} }
public class SistemaLogAntes extends Sistema{ public void fazIsso(){
System.out.println(“Vai fazer isso!”);
super.fazIsso();
} }
Decorator
Decorator
Solução
O objeto decorador contém o objeto decorado O objeto decorador tem a interface do decorado O objeto decorador repassa (delega) ao decorado o
Decorator
Conseqüências
Permite adicionar e remover
responsabilidades de uma classe em tempo de execução (dinamicamente)
• Sistema normal ou com log poderiam ser instanciados a qualquer momento
Alternativa flexível a generalização/ especialização para extensão de
Padrões comportamentais
Caracteriza a forma como os objetos irão interagir para realizar um dado comportamento Observer Chain of responsibility Command State Strategy Template Method
Observer
Problema
Como informar objetos interessados que um objeto foi modificado
Ficar chamando métodos testando de tempos em tempos se mudou não é
viável
• Controle difícil
Alternativa: objeto que muda avisa os outros
Observer
Solução
Encapsula dependência de um objeto em relação a outros • Observador registra-se em um sujeito (aquele que muda)
• Sempre que o sujeito muda seu estado, ele notifica todos seus observadores registrados
Observer
Exemplo de Solução
Outros exemplos: tratamento de eventos em Java,
Observer
Conseqüências
Permite que objetos registrem
dinamicamente suas dependências de outros objetos
Permite atualizar um conjunto de objetos quando um certo objeto sofrer modificação
Também conhecido como publisher-subscriber (ou event-listener em Java)
Chain of Responsibility
Problema
Acoplamento entre cliente que envia um
pedido de comando e objeto que executa o comando
Sistema de help sensitivo
• Não dá para saber qual janela tem um help específico
• Programa de interface gráfica tem que chamar o help da primeira janela, do menor componente
para o maior, que possui Help
• Cliente que testa com condições (if) seria dificílimo de manter
Chain of Responsibility
Exemplo de Solução
Corrente (chain) de objetos do
objeto mais específico para o mais geral
Passar o pedido para a frente até
que alguém o receba
Parecido com o mecanismo de
Diferença entre Observer e COR
Observer (em paralelo)
Chain of Responsibility
Solução
Reduz acoplamento entre objeto que envia
comando e aquele que recebe
Chain of Responsibility
Conseqüências
Não garante que um comando será tratado
• Comandos não tratados serão ignorados Se o número de objetos fica muito
grande, preocupação com eficiência
• Problema: muitas passagens por objetos sem tratar o comando
Command
Problema
• Complexidade de comandos em um aplicações interativas
• Aplicação dependente da aplicação do comando nos objetos e registrar
Command
Exemplo: editor de figuras
• Cliente fica acoplado aos detalhes das operações
Vamos encapsular invocações de métodos em objetos
• Assim podemos guardar informações sobre a execução do método
//tratador do evento de menu if (menu==Menu.RECORTAR){
//acoes para realizar recorte da figura
//armazenar o que foi feito para undo,redo }
if (menu==Menu.COPIAR){
//acoes para realizar copia da figura
//armazenar o que foi feito para undo,redo }
Command
Command
Solução
Definir uma interface de comandos fácil de montar e
fazer undo, redo
Objeto comando encapsula todos os detalhes do
Command
Conseqüências
Permite tornar a execução de
operações mais flexível (ex: desfazer) Comando pode ser parametrizado para
pedidos diferentes, fila de pedidos e suporte para operações que podem
State
Problema
Objetos em diferentes categorias que mudam de
estado de tempos em tempos
Herança neste caso define dificuldades de extensão Exemplo: há mais de um limite, a conta muda de status
public class Conta...
public class ContaRed extends Conta...
public class ContaSilver extends Conta... Conta c = procuraConta(numero);
c.creditar(100.0);
if (c instanceof ContaRed && c.getSaldo>LIMIT){ c = new ContaSilver(..);//copiar do objeto antes }
State
State
Solução
Permite a mudança de estado de um objeto
dinamicamente
Mais util ainda quando a mudança de estado provoca
um comportamento diferente
Subclasses de State representam comportamento
State
Conseqüências
Mudança de estado e adição de novos estados ficam diretas
Mais um caso de delegação em vez de herança
Strategy
Problema
Variação de comportamento difícil de manter
public class Vestibular { ...
public void ordenarLista(int tipoOrdenacao){ if (tipoOrdenacao == BUBBLE)
//fazer ordenacao bubble sort da lista if (tipoOrdenacao == INSERTION)
//fazer ordenacao insertion sort da lista if (tipoOrdenacao == QUICKSORT)
//fazer ordenacao quick sort da lista }
Strategy
Problema
Com herança: variação definida estaticamente Neste caso, herança indevida
public class Vestibular { ...
public abstract void ordenarLista(); }
public class VestibularQuick extends Vestibular { ...
public void ordenarLista(){
//ordenacao sempre quicksort }
Strategy
Strategy
Solução
Encapsula algoritmos relacionados em classes que são
subclasses de uma classe comum
Permite a seleção de algoritmo variar por objeto e
Strategy
Conseqüências
Permite múltiplas variações de comportamento em tempo de
execução, de acordo com uma opção Variações comportamentais
encapsuladas em uma classe separada Superclasse da estratégia permite
esconder do cliente os detalhes de implementação
Template Method
Problema
Maior parte de um método é geral para todas as
situações, mas partes são específicas
Difícil de testar e reusar
public class ConsultaBancoDados { ...
public Repositorio efetuarConsulta(String par){
if (this.banco == ORACLE)
formatarConexaoOracle();
else formatarConexaoSQLServ();
conectar();
rep = efetuarConsulta (par); return rep;
Template Method
Template Method
Solução
A classe concreta define como o algoritmo (método
template) será executado em alguns pontos específicos
Template Method
Conseqüências
Os clientes precisam especializar a classe para definir o comportamento completo
Uma fábrica (factory) poderia ser usada para facilitar a criação
Referência adicional
Deem uma olhada em: