UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de...

Post on 18-Dec-2018

214 views 0 download

Transcript of UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de...

UNIFEI Universidade Federal de ItajubáInstituto de Engenharia de Sistemas e Tecnologias da Informação-IESTI

Disciplina CCO002 – Engenharia de SoftwareProfessor Enzo Seraphim

1 Padrões de ResponsabilidadeA decomposição em classes e objetos distribui responsabilidades em cada objeto e método do sistema.Responsabilidades podem ser controladas usando encapsulamento e controle de acesso, definindo:

● interfaces para clientes de objetos (public)● interfaces para clientes de classes (protected)● dados e operações internas à classe (private)● Design patterns utilizam esses recursos para ir além e oferecer controle mais preciso● Controle distribuído em objetos específicos● Controle centralizado em um único objeto● Notificação e intermediação de requisições

Padrões orientados a responsabilidades lidam com situações em que é preciso fugir da regra comumque a responsabilidade deve ser distribuída ao máximo:

● Singleton: centraliza a responsabilidade em uma única instância de uma classe● Observer: desacopla um objeto do conhecimento de que outros objetos dependem dele● Mediator: centraliza a responsabilidade em uma classe que determina como outros objetos

interagem● Proxy: assume a responsabilidade● Chain of Responsibility: permite que uma requisição passe por uma corrente de objetos até

encontrar um que a processe● Flyweight: centraliza a responsabilidade em objetos compartilhados de alta granularidade

1.1 Objeto Único - Singleton

"Garantir que uma classe só tenha uma única instância, e prover um ponto de acesso global a ela."[GoF]

Algumas classes devem ter uma única instância. Deve existir exatamente um planeta terra, um printspooler, uma saída padrão e um gerenciador de janelas. O padrão singleton assegura que apenas umobjeto da classe será criado e fornece um ponto onde este objeto é manipulado. A própria classe,através de seus métodos estáticos, criará sua instância.

Problema● Garantir que apenas um objeto exista, independente do número de requisições que receber

para criá-lo.● Como controlar (contar) o número de instâncias da classe?● Como armazenar a(s) instância(s)?● Como controlar ou impedir a construção normal? Se for possível usar new e um construtor

para criar o objeto, há como limitar instâncias?● Como definir o acesso à um número limitado de instâncias (no caso, uma apenas)?● Como garantir que o sistema continuará funcionando se a classe participar de uma hierarquia

de classes?

Aplicações● Um único banco de dados● Um único acesso ao arquivo de log● Um único objeto que representa um vídeo● Uma única fachada (Façade pattern)

Estrutura

Exemplo

Vantagens● Acesso central e extensível a recursos e objetos● Pode ter subclasses* (o que seria impossível se fosse apenas usada uma classe com métodos

estáticos)

Desvantagens● Qualidade da implementação depende da linguagem● Difícil de testar (simulações dependem de instância extra)● Implementação complicada em ambiente multithreaded e em ambiente distribuído

Exemplo Java

public class ContadorGlobal { private ContadorGlobal () {} private static int numero = 1; private static ContadorGlobal instancia = new ContadorGlobal (); public static ContadorGlobal getInstancia() {return instancia;} public static void incrementa () { numero++;} public static int getNumero() {return numero;}}

import java.io.*; public class Principal{ public static void main(String[] args) { ContadorGlobal c1, c2, c3; //c1 = new ContadorGlobal (); // nao compila! c2 = ContadorGlobal.getInstancia (); c3 = ContadorGlobal.getInstancia (); if (c2 == c3) { System.out.println("c2 e c3 são mesmo objeto!"); } c2.incrementa (); System.out.println("c2 = " + c2.getNumero ()); System.out.println("c3 = " + c3.getNumero ()); c3.incrementa (); System.out.println("c2 = " + c2.getNumero ()); System.out.println("c3 = " + c3.getNumero ()); }}

1.2 Observador - Observer"Definir uma dependência um-para-muitos entre objetos para que quando um objeto mudar de estado,todos os seus dependentes sejam notificados e atualizados automaticamente." [GoF]

Problema

Como garantir que objetos que dependem de outro objeto fiquem atualizados com as mudanças?Como fazer com que os observadores tomem conhecimento do objeto de interesse?Como fazer com que o objeto de interesse atualize os observadores quando seu estado mudar?

Observador Sujeitocadastra

notifica

Estrutura

Os dados podem ser modificados por um cliente ou por um dos observadores.Evitar o acoplamento entre os observadores é a função do padrão Observador. Ele define um objetosujeito e vários observadores. Quando o sujeito é modificado, os observadores são notificados. Osobservadores são previamente registrados com o sujeito.Exemplo

Consequências● Há um acoplamento entre o sujeito e seus observadores;● Os observadores podem ser adicionados e removidos em execução.

public abstract class Encargo { abstract public void atualizar(double valor);}public class Inss extends Encargo { private double valorInss=0d; public void atualizar(double valor) { valorInss = valor * 0.1; } public double getValorInss() { return valorInss; }}public class Pis extends Encargo { private double valorPis=0d; public void atualizar(double valor) { valorPis = valor * 0.03; } public double getValorPis() {return valorPis; }}public abstract class Trabalhista { private List<Encargo> encargos = new ArrayList<Encargo>(); protected void notificar(double valor) { Iterator<Encargo> it = this.iteratorEncargo(); for(int n=0; n < this.sizeOfEncargo(); n++){ it.next().atualizar(valor); } } }public class Folha extends Trabalhista { private double SalContrib = 0;

public double getSalContrib() { return SalContrib; } public void setSalContrib(double salContrib) { SalContrib = salContrib; notificar(salContrib); }}public class App { public static void main(String args[]){ Folha f = new Folha(); Pis p = new Pis(); f.addEncargo(p); Inss i = new Inss(); f.addEncargo(i); f.setSalContrib(1000); System.out.println("pis=" + p.getValorPis()); System.out.println("inss=" + i.getValorInss()); }}

1.3 Mediador - Mediator"Definir um objeto que encapsula como um conjunto de objetos interagem. Mediator promoveacoplamento fraco ao manter objetos que não se referem um ao outro explicitamente, permitindovariar sua interação independentemente." [GoF]

Estrutura

Um objeto Mediador deve encapsular toda a comunicação entre um grupo de objetos● Cada objeto participante conhece o mediador, mas ignora a existência dos outros objetos● O mediador conhece cada um dos objetos participantes

A interface do Mediador é usada pelos colaboradores para iniciar a comunicação e recebernotificações:

● O mediador recebe requisições dos remetentes● O mediador repassa as requisições aos destinatários● Toda a política de comunicação é determinada pelo mediador (geralmente através de uma

implementação concreta do mediador)

Problema

Como permitir que um grupo de objetos se comunique entre si sem que haja acoplamento entre eles?● Como remover o forte acoplamento presente em relacionamentos muitos para muitos?● Como permitir que novos participantes sejam ligados ao grupo facilmente?

AplicaçãoUse o padrão mediador o relacionamento de associação for bidirecional e um método de cada classesdevem ser executado, não importando a cardinalidade;

Exemplo

Conseqüências● Desacoplamento colegas;● Evita relacionamento cíclico nas linguagens de programação;● Abstrai os relacionamentos entre colegas no mediador.

Exemplo Javaabstract class Mediador { abstract public void OperacaoMediada();}abstract class Colaborador{ private Mediador mediador; public void chamarOperacao() { mediador.OperacaoMediada(); }; public Mediador getMediador () {return mediador; } public void setMediador (Mediador m) { mediador = m; }}class ColaboradorGato extends Colaborador { private int velocidade = 0; public void PersegueRato() { velocidade = velocidade + 5; } public int getVelocidade() { return velocidade; }}class ColaboradorRato extends Colaborador { private int velocidade = 0; public void FogeGato() { velocidade = velocidade + 6; } public int getVelocidade() { return velocidade; }}class MediadorGatoRato extends Mediador { private ColaboradorGato gato; private ColaboradorRato rato; public ColaboradorGato getGato() { return gato; } public void setGato(ColaboradorGato g) { gato = g; } public ColaboradorRato getRato() {return rato; }

public void setRato(ColaboradorRato r) { rato = r; } public void OperacaoMediada(){ if (gato!=null) gato.PersegueRato(); if (rato!=null) rato.FogeGato(); }}public class Principal { public static void main(String[] args) { ColaboradorGato g = new ColaboradorGato(); ColaboradorRato r = new ColaboradorRato(); MediadorGatoRato m = new MediadorGatoRato(); m.setGato(g); m.setRato(r); r.setMediador(m); g.setMediador(m); System.out.println("velocidade gato = " + g.getVelocidade() ); System.out.println("velocidade rato = " + r.getVelocidade() ); r.chamarOperacao(); System.out.println("velocidade gato = " + g.getVelocidade() ); System.out.println("velocidade rato = " + r.getVelocidade() ); g.chamarOperacao(); System.out.println("velocidade gato = " + g.getVelocidade() ); System.out.println("velocidade rato = " + r.getVelocidade() ); }}

1.4 Procurador - Proxy

"Prover um substituto ou ponto através do qual um objeto possa controlar o acesso a outro." [GoF]

Estrutura

Cliente usa intermediário em vez de sujeito real Intermediário suporta a mesma interface que sujeito realIntermediário contém uma referência para o sujeito real e repassa chamadas, possivelmente,acrescentando informações ou filtrando dados no processoExemplo

Aplicabilidade● um procurador pode representar um objeto que está em outra máquina. As chamadas são

enviadas pela rede ao objeto remoto;● um procurador pode controlar o acesso a um outro objeto, proibindo operações críticas.

Vantagens● Transparência: mesma sintaxe usada na comunicação entre o cliente e sujeito real é usada no

proxy● Permite o tratamento inteligente dos dados no cliente● Permite maior eficiência com caching no cliente

Exemplo Javapublic abstract class Banco{ public abstract boolean emprestimo(float v);}public class Brasil extends Banco{ private Central central = null; public void setCentral(Central v) { central=v; } public Central getCentral() { return central; } public boolean emprestimo(float v){ return central.emprestimo(v); }}public class Central extends Banco{ private float dinheiro; public float getDinheiro() { return dinheiro; } public void setDinheiro(float v) { dinheiro = v; } public boolean emprestimo(float v){ if(dinheiro >= v){ dinheiro -= v; return true; } else return false; }}public class Empresa{ private Banco banco = null; public void setBanco(Banco v) { banco = v; } public Banco getBanco() { return banco; } public boolean pedirEmprestimo(int i){ if(banco != null) return banco.emprestimo(i); return false; }}public class App { public static void main(String[] args) { Central c = new Central(); c.setDinheiro(100); Brasil b = new Brasil(); b.setCentral(c); Empresa e = new Empresa(); e.setBanco(b); e.pedirEmprestimo(50); System.out.println("saldo BC = " + c.getDinheiro()); }}

1.5 Cadeia de Responsabilidades - Chain of Responsibilities"Evita acoplar o remetente de uma requisição ao seu destinatário ao dar a mais de um objeto a chancede servir a requisição. Compõe os objetos em cascata e passa a requisição pela corrente até que um objeto a sirva." [GoF]

AplicabilidadeQuando vários objetos podem responder um requerimento, mas a decisão de quem responde só pode ser resolvida em execução.

Estrutura

Exemplo

Exemplo de Objetos

Conseqüências● o acoplamento é reduzido. O emissor do requerimento e o receptor não se conhecem;● a responsabilidade por responder a um requerimento pode ser modificada em execução;● pode ser que ninguém na cadeia de objetos possa responder a um requerimento insegura.

Exemplo Javaabstract public class Notas { protected Notas prox = null; protected static int ultimaserie; protected int serie; public abstract int soma(); public int getSerie() { return serie; } public static Notas criarNotas(int v) { Notas cab=null; if((int)v/10>=1){ cab=new Nota10(); v-=10; }else if((int)v/5>=1){ cab=new Nota5(); v-=5; }else if((int)v/1>=1){ cab.prox=new Nota1(); v-=1; } Notas aux=cab; while(v>0){ if((int)v/10>=1){ aux.prox=new Nota10();

v-=10; }else if((int)v/5>=1){ aux.prox=new Nota5(); v-=5; }else{ aux.prox=new Nota1(); v-=1; } aux = aux.prox; } return cab; }}

public class Nota10 extends Notas{ public Nota10(){ ultimaserie++; serie=ultimaserie; } public int soma() { int soma = 10; if(prox!=null) soma += prox.soma(); return soma; }}public class Nota5 extends Notas{ public Nota5(){ ultimaserie++; serie=ultimaserie; } public int soma() { int soma = 5; if(prox!=null) soma += prox.soma(); return soma; }}public class Nota1 extends Notas{ public Nota1(){ ultimaserie++; serie=ultimaserie; } public int soma() { int soma = 1; if(prox!=null) soma += prox.soma(); return soma; }}public class Cheque { private Notas notas=null; private int valor=0; public Cheque(){} public int getValor(){ return valor; } public void setValor(int v){ valor=v; } public void desconta(){ notas=Notas.criarNotas(valor); } public int somaNotas(){ return notas.soma(); }}import java.util.*;public class App{ public static void main(String[] args){ Scanner in = new Scanner (System.in); Cheque c = new Cheque(); System.out.println("digite valor cheque:"); c.setValor( in.nextInt() ); c.desconta(); System.out.println("soma das notas: " + c.somaNotas()); }}

1.6 Peso Mosca - Flyweight

"Usar compartilhamento para suportar grandes quantidades de objetos refinados eficientemente." [GoF]

Estrutura

Um peso-mosca é um objeto compartilhado que pode ser usado em múltiplos contextossimultâneamente. O estado intrínseco consiste de informações independentes do contexto do peso-mosca. O estado extrínseco depende e varia com o contexto do peso-mosca e, portanto, não pode sercompartilhado.

• A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuarsobre estados extrínsecos.

• A classe Concreto implementa a interface do Flyweight e adiciona estados intrínsecos seexistirem. Essa classe precisa ser compartilhada e qualquer estado que ela armazene precisaser intrínseco.

• A classe ConcretoNaoCompartilhado são objetos não compartilhados. Nem todas as subclassesque implementam Flyweight precisam ser compartilhadas.

• A classe FabricaFlyweight verifica se ainda não criada a referência antes de cria-lo, casocontrário retorna a referência que já existe.

• A classe Cliente armazena referencias para os objetos dos estados extrínsecos do FlyWeight.

Exemplo

Aplicabilidade● Quando o tamanho do conjunto de objetos for significativamente menor que a quantidade de

vezes em que eles são usados na aplicação(Custos de armazenamento críticos).● Quando objetos podem ser usados em diferentes contextos ao mesmo tempo (agindo sempre

como um objeto indepentente).● Quando a maior parte do estado do objeto possa ser tornado extrínseco.● Quenado grandes grupos de objetos podem ser substituídos por poucos objetos

compartilhados depois de se separar o estado extrínseco do intrínseco.● Quando a aplicação não depende da identidade dos objetos.

Quando não usar● Quando o estado dos objetos não for imutável (é preciso passar o estado mutável como

parâmetro e isto pode ser impraticável se o estado consistir de vários objetos).

● Quando for necessário elaborar um algoritmo ou algo complicado para separar objetos mutáveis de imutáveis

ConseqüênciasPodem ser introduzidos custos em termos de eficiência devido à transferência, procura e/oucomputação do estado extrínseco, compensados pela economia de memória. A economia de memória resulta de vários factores: redução do número de instâncias; quantidade deestado intrínseco se o estado extrínseco é calculado ou armazenado.

Exemplo:Compartilhar objetos que representam os caracteres no documento:Estado intrínseco - Código dos caracteresEstado extrínseco - Posicionamento dos caracteres;

O padrão Flyweight permite-nos utilizar um objeto para cada caráter sem utilizar uma grandequantidade de objetos. Caracteres idênticos em posições diferentes do texto utilizam o mesmo objeto.

Exemplo Java

public abstract class Caracter { public abstract void setSimbolo(char v); public abstract char getSimbolo();}

public class Letra extends Caracter{ private char letra; public char getSimbolo() { return letra; } public void setSimbolo(char simbolo) { this.letra = simbolo; } }

public class Pontuacao extends Caracter { private char pontuacao; public char getSimbolo() { return pontuacao; } public void setSimbolo(char simbolo) { this.pontuacao = simbolo; }}

public class Alfabeto { private List<Caracter> caracteres = new ArrayList<Caracter>(); public Caracter getCaracter(char c){ Caracter caract=null; char low = Character.toLowerCase(c); if((low >= 'a') && (low <= 'z')){ Iterator<Caracter> it = iteratorCaracter(); while(it.hasNext()){ Caracter ca = it.next(); if(ca.getSimbolo()==c){ caract = ca; break; } } if(caract==null){ Letra l = new Letra(); l.setSimbolo(c); caracteres.add(l); caract = l; } }else{ Pontuacao p = new Pontuacao(); p.setSimbolo(c); caracteres.add(p); caract = p; } return caract; } public int sizeOfCaracter(){ return caracteres.size(); } public Iterator<Caracter> iteratorCaracter(){ return caracteres.iterator(); }

}

public class Posicao { private int paragrafo; private int sentenca; private static Alfabeto alfabeto = new Alfabeto(); private Caracter caracter; public Posicao(int par, int sen, char c){ paragrafo = par; sentenca = sen; caracter = alfabeto.getCaracter(c); } public int getParagrafo() { return paragrafo; } public int getSentenca() { return sentenca; } public static Alfabeto getAlfabeto() { eturn alfabeto; }}

public class App { public static void main(String args[]) { String hino = "Ouviram do Ipiranga as margens plácidas " ... + "Pátria amada, Brasil!"; int i = 0; int par=0; int sen=0; Posicao pos[] = new Posicao[hino.length()]; for (i = 0; i < hino.length(); i++) { char c = hino.charAt(i); pos[i] = new Posicao(par, sen, c); if(c == ' ') sen++; if(c == '.') par++; } System.out.println("total letras=" + hino.length()); System.out.println("total simbolos=" + Posicao.getAlfabeto().sizeOfCaracter()); System.out.println("IMPRIMIR SIMBOLOS"); Iterator<Caracter> it1 = Posicao.getAlfabeto().iteratorCaracter(); while (it1.hasNext()) { System.out.print("[" + it1.next().getSimbolo() + "]"); i++; if (i % 10 == 0) { System.out.println(); } } }}