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

12
UNIFEI Universidade Federal de Itajubá Instituto de Engenharia de Sistemas e Tecnologias da Informação-IESTI Disciplina CCO002 – Engenharia de Software Professor Enzo Seraphim 1 Padrões de Responsabilidade A 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 comum que 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 print spooler, uma saída padrão e um gerenciador de janelas. O padrão singleton assegura que apenas um objeto 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

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

Page 1: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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

Page 2: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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

Page 3: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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;

Page 4: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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

Page 5: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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; }

Page 6: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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

Page 7: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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

Page 8: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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();

Page 9: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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]

Page 10: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

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).

Page 11: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

● 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(); }

Page 12: UNIFEI - Tópicos Especiais em Programação · • A classe Flyweight define uma interface de entrada para os Flyweights. Pode receber e atuar sobre estados extrínsecos. • A classe

}

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(); } } }}