1 Padrões de Construção

Propaganda
UNIFEI
Disciplina
Professor
Universidade Federal de Itajubá
Instituto de Engenharia de Sistemas e Tecnologias da Informação-IESTI
CCO002 – Engenharia de Software
Enzo Seraphim
1 Padrões de Construção
A maneira padrão de construir objetos em uma linguagem orientada à objetos é através de
construtores. Toda classe tem um construtor: operação declarada com o mesmo nome da classe, que
não retorna valor e só pode ser usada na inicialização. Se um construtor não é explicitamente
declarado em uma classe, o sistema cria um construtor default para a classe.
O construtor é responsável por criar uma instância de seu objeto e alocar qualquer memória ou
inicializar qualquer campo necessário de forma que o objeto esteja em estado de uso depois da saída
do construtor. Portanto, o construtor é uma oportunidade de inicializar de forma organizada as
características dos objetos.
Os métodos construtores são definidos definindo um método com o mesmo nome da classe. Toda
classe pode ter um ou mais construtores, mas apenas um deve ser executado para cria o objeto.
Dependendo do tipo do objeto, o construtor pode ter diferentes números de parâmetros. Para que uma
classe seja instanciada em java deve ser declarado um construtor.
Todo construtor inicializa a hierarquia de classes do objeto antes de executar e sempre contém ou
uma referência à superclasse (implícita ou explícita) ou uma referência a outro construtor da classe
como primeira ou única instrução
A definição da classe coisa, “public class Coisa {}” é igualmente declarada usando a sintaxe abaixo:
01:
02:
03:
04:
05:
public class Coisa extends java.lang.Object {
public Coisa() {
super();
}
}
O compilador insere o construtor, a super classe e a chamada para construtor padrão mesmo se forem
omitidos na declaração.
O exemplo abaixo define uma classe chamada coisa com um membro nome.
01:
02:
03:
04:
05:
06:
public class Coisa {
private String nome = "Ainda Sem Nome";
public Coisa(String nome) {
this.nome = nome;
}
}
O exemplo abaixo define uma classe OutraCoisa que herda os membros de Coisa. Note que o
construtor dessa classe chama o construtor da super classe.
01:
02:
03:
04:
05:
06:
public class OutraCoisa extends Coisa{
private int idade = 10;
public OutraCoisa() {
super("Outra Coisa");
}
}
Existem 3 problemas para utilização de construtores: cliente pode não ter todos os dados necessários
para instanciar um objeto; cliente fica acoplado a uma implementação concreta (precisa saber a classe
concreta para usar new com o construtor); cliente de herança pode criar construtor que chama
métodos que dependem de valores ainda não inicializados.
Os padrões que oferecem alternativas à construção de objetos:
● Builder: obtém informação necessária em passos antes de requisitar a construção de um objeto
● Factory Method: adia a decisão sobre qual classe concreta instanciar
● Abstract Factory: construir uma família de objetos que compartilham um "tema" em comum
● Prototype: especificar a criação de um objeto a partir de um exemplo fornecido
● Memento: reconstruir um objeto a partir de uma versão que contém apenas seu estado interno
1.1 Construtor - 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." [GoF]
Estrutura
Exemplo
Aplicação
●
●
●
●
Builder permite que uma classe se preocupe com apenas uma parte da construção de um
objeto. É útil em algoritmos de construção complexos .
Use-o quando o algoritmo para criar um objeto complexo precisar ser independente das partes
que compõem o objeto e da forma como o objeto é construído.
Builder também suporta substituição dos construtores, permitindo que a mesma interface seja
usada para construir representações diferentes dos mesmos dados.
Use quando o processo de construção precisar suportar representações diferentes do objeto
que está sendo construído.
Exemplo Java
public abstract class Movel{
private String material;
public String getMaterial(){return material;};
public void setMaterial(String v){material=v;};
}
public class Cama extends Movel{
private int tipo;
public int getTipo(){return tipo;}
public void setTipo(int v){tipo=v;}
}
public class GuardaRoupa extends Movel{
private int porta;
public int getPorta(){return porta;}
public void setPorta(int v){porta=v;}
}
import java.util.*;
public class Quarto{
List <Movel> movel = new ArrayList<Movel>();
public Quarto() {
movel.add(new Cama());
movel.add(new GuardaRoupa());
}
public Movel getMovel(int id){
if (movel.size()>id) return movel.get(id);
else return null;
}
}
1.2 Método Fábrica - Factory Method
"Definir uma interface para criar um objeto mas deixar que subclasses decidam que classe instanciar.
Factory Method permite que uma classe delegue a responsabilidade de
instanciamento às
subclasses." [GoF]
Problema
● É possível criar um objeto sem ter conhecimento algum de sua classe concreta?
● Esse conhecimento deve estar em alguma parte do sistema, mas não precisa estar no cliente
● FactoryMethod define uma interface comum para criar objetos
● O objeto específico é determinado nas diferentes implementações dessa interface
● O cliente do FactoryMethod precisa saber sobre implementações concretas do objeto criador
do produto desejado
Estrutura
Exemplo
Exemplo usando classe genérica
Vantagens
●
●
●
Criação de objetos é desacoplada do conhecimento do tipo concreto do objeto
Conecta hierarquias de classe paralelas
Facilita a extensibilidade
Exemplo Java
public abstract class Roupa {
private int tamanho;
public int getTamanho(){return tamanho;}
public void setTamanho(int v){tamanho=v;}
}
public class Camisa extends Roupa{
private boolean mangaCurta;
public boolean getMangaCurta(){return mangaCurta;}
public void getMangaCurta(boolean v){mangaCurta=v;}
}
public class Calca extends Roupa{
private boolean frio;
public boolean getFrio(){return frio;}
public void getFrio(boolean v){frio=v;}
}
public abstract class Criador {
public abstract Roupa fabricaRoupa();
}
public class Costureira extends Criador {
private String nome;
public String getNome(){return nome;}
public void setNome(String v){nome=v;}
public Roupa fabricaRoupa() {return new Calca();}
}
public class Confeccao extends Criador{
private String modeloMaq;
public String getModelMaq(){return modeloMaq;}
public void setModelMaq(String v){modeloMaq=v;}
public Roupa fabricaRoupa() {return new Camisa();}
}
1.3 Fábrica Abstrata - Abstract Factory
"Prover uma interface para criar famílias de objetos relacionados ou dependentes sem especificar
suas classes concretas." [GoF]
Estrutura
Exemplo
Aplicabilidade
Este padrão deve ser utilizado quando o programa deve ser configurado por famílias de classes. Todas
as classes de uma mesma família devem ser utilizadas em conjunto.
Consequências
● Fábrica abstrata permite a troca de toda uma coleção de classes sem grandes modificações no
programa fonte;
● As classes concretas são conhecidas apenas pela fábrica abstrata;
● É difícil colocar classes novas no programa. É necessário acrescentar métodos na classe
fábrica abstrata e em todas as subclasses;
● As classes dos produtos devem ter uma interface comum. Talvez seja necessário restringi-las
para conseguir este objetivo.
Exemplo Java
public abstract class Anel { }
public class AnelBijuteria extends Anel{
private int tipoPedra;
private int qtdPedra;
public int getTipoPedra(){return tipoPedra;};
public void setTipoPedra(int v){tipoPedra=v;};
public int getQtdPedra(){return qtdPedra;};
public void setQtdPedra(int v){qtdPedra=v;};
}
public class AnelOuro extends Anel{
private int tipoPreciosa;
private int qtdPreciosa;
public int getTipoPreciosa(){return tipoPreciosa;};
public void setTipoPreciosa(int v){tipoPreciosa=v;};
public int getQtdPreciosa(){return qtdPreciosa;};
public void setQtdPreciosa(int v){qtdPreciosa=v;};
}
public abstract class Colar {
private int qtdPreciosa;
public int getQtdPreciosa(){return qtdPreciosa;}
public void setQtdPreciosa(int v){qtdPreciosa=v;}
}
public class ColarBijuteria extends Colar{
private int tipoMaterial;
public int getTipoMaterial(){return tipoMaterial;}
public void setTipoMaterial(int v){tipoMaterial=v;}
}
public class ColarOuro extends Colar{
private int quilate;
public int getQuilate(){return quilate;}
public void setQuilate(int v){quilate=v;}
}
public abstract class Joalheiro {
public abstract Colar novoColar();
public abstract Anel novoAnel();
}
public class JoalheiroBijuteria extends Joalheiro{
public Colar novoColar() {return new ColarBijuteria();}
public Anel novoAnel() {return new AnelBijuteria();}
}
public class JoalheiroOuro extends Joalheiro{
public Colar novoColar() {return new ColarOuro();}
public Anel novoAnel() {return new AnelOuro();}
}
1.4 Protótipo - Prototype
"Especificar os tipos de objetos a serem criados usando uma instância como protótipo e criar novos
objetos ao copiar este protótipo." [GoF]
Estrutura
Exemplo
Exemplo usando Curiously Recurring Template Pattern (CRTP)
Exemplo Java
public abstract class Midia {
protected String titulo;
public String getTitulo(){return titulo;}
public void setTitulo(String v){titulo=v;}
public abstract Midia clone();
}
public class Conserto {
private Midia midia;
public Midia getMidia(){return midia;}
public void setMidia(Midia v){midia=v.clone();}
}
public class Video extends Midia{
private String produtora;
private String diretor;
public String getProdutora(){return produtora;}
public void setProdutora(String v){produtora=v;}
public String getDiretor(){return diretor;}
public void setDiretor(String v){diretor=v;}
public Midia clone() {
Video v = new Video();
v.setTitulo(titulo);
v.setProdutora(produtora);
v.setDiretor(diretor);
return v;
}
}
public class Jogo extends Midia{
private String fabricante;
private int console;
public String getFabricante(){return fabricante;}
public void setFabricante(String v){fabricante=v;}
public int getConsole(){return console;}
public void setConsole(int v){console=v;}
public Midia clone() {
Jogo j = new Jogo();
j.setTitulo(titulo);
j.setFabricante(fabricante);
j.setConsole(console);
return j;
}
}
public class Musical extends Midia{
private String autor;
private String produtora;
public String getAutor(){return autor;}
public void setAutor(String v){autor=v;}
public String getProdutora(){return produtora;}
public void setProdutora(String v){produtora=v;}
public Midia clone() {
Musical m = new Musical();
m.setTitulo(titulo);
m.setAutor(autor);
m.setProdutora(produtora);
return m;
}
}
Conseqüências
● padrão Prototype permite que um cliente crie novos objetos ao copiar objetos existentes
● padrão protótipo esconde as classes dos objetos das sub-classes para os clientes;
● Object.clone() pode ser usado como implementação do Prototype pattern em Java mas é
preciso lembrar que ele só faz cópias rasas: é preciso copiar também cada objeto membro e
seus campos recursivamente.
Vantagem
● Criar objetos deste modo é poder aproveitar o estado existente de um objeto
1.5 Recordador - Memento
"Sem violar o encapsulamento, capturar e externalizar o estado interno de um objeto para que o
objeto possa ter esse estado restaurado posteriormente." [GoF]
Estrutura
O padrão memento é utilizado para armazenar e restaurar futuramente o estado de um objeto..
Aplicabilidade
● Um snapshot do (parte do) estado de um objeto precisa ser armazenada para que ele possa ser
restaurado ao seu estado original posteriormente
● Uma interface direta para se obter esse estado iria expor detalhes de implementação e quebrar
o encapsulamento do objeto
● Recordador permite capturar o estado de um objeto para que seja possível recuperá-lo
posteriormente
● O meio de armazenamento utilizado depende de quando o objeto terá que ser recuperado e dos
riscos envolvidos na não recuperação
● A aplicação mais comum de memento é o suporte a operações de Undo.
● Um memento é um pequeno repositório para guardar estado dos objetos
● Pode-se usar outro objeto, um string, um arquivo
● Recordador guarda um snapshot no estado interno de outro objeto - a Fonte
● Um mecanismo irá requisitar um memento da fonte quando ele necessitar verificar o estado
desse objeto
● A fonte reinicializa o memento com informações que caracterizam seu estado atual
● Só a fonte tem permissão para recuperar informãções do memento (o memento é "opaco" aos
outros objetos)
Exemplo
Consequências
● não violam a proteção de informação;
● podem usar muita memória.
Exemplo Java
public class Endereco {
private String logradouro;
public Endereco(String v){logradouro=v;}
public String getLogradouro() {return logradouro;}
public void setLogradouro(String v) {logradouro=v;}
}
import java.util.*;
public class Historico {
private List<Endereco> end=new ArrayList<Endereco>();
public int size() {return end.size();}
public void add(Endereco e) {end.add(e);}
public Endereco get(int id) {return end.get(id);}
}
public class Cliente {
private Historico histo=new Historico();
private String nome;
private String logradouro;
private int pos=0;
private void setRecordador(Endereco v) {logradouro=v.getLogradouro();}
public String getNome(){return nome;}
public void getNome(String v){nome=v;}
public String getLogradouro(){return logradouro;}
public void getLogradouro(String v){logradouro=v;}
public void createEndereco() {
histo.add(new Endereco(logradouro));
pos=histo.size();
}
public boolean desfazerEnd(){
if(pos>0){
pos--;
setRecordador(histo.get(pos-1));
return true;
}else return false;
}
public boolean refazerEnd(){
if(pos<histo.size()){
pos++;
setRecordador(histo.get(pos-1));
return true;
}else return false;
}
}
Download