Baixe o app para aproveitar ainda mais
Prévia do material em texto
Programação Avançada Prof. Anderson B. Pinheiro 2019.1 Padrões de Projeto Estruturais Padrões Estruturais As interações entre os objetos de um sistema podem gerar fortes dependências Aumentando a complexidade de eventuais alterações do sistema Custo de manutenção aumenta Padrões estruturais buscam reduzir o acoplamento entre os objetos Padrões Estruturais Adapter – Permitir que um objeto seja substituído por outro que, apesar de realizar a mesma tarefa, possui uma interface diferente. Bridge – Separar uma abstração de sua representação, de forma que ambos possam variar e produzir tipos de objetos diferentes Composite – Agrupar objetos que fazem parte de uma relação parte-todo de forma a tratá-los sem distinção Decorator – Adicionar funcionalidades a um objeto dinamicamente Padrões Estruturais Facade – Prover uma interface simplificada para a utilização de várias interfaces de um subsistema Front Controller – Centralizar todas as requisições a uma aplicação web Flyweight – Compartilhar, de forma eficiente, objetos que são usados em grande quantidade Proxy – Controlar as chamadas a um objeto através de outro objeto de mesma interface Adapter O padrão Adapter é utilizado quando necessário ligar uma nova biblioteca de classes a um sistema já existente Em geral, com interfaces diferentes A solução é criar uma classe que funcione como um adaptador Adaptando a interface do novo fornecedor ao formato que o sistema já conhece Compatibilizando um sistema a diferentes frameworks ou APIs que possam vir a ser implementadas Alvo: define a interface específica do domínio da aplicação Adaptado: define uma interface existente que precisa ser adaptada Adaptador: adapta a interface do Adaptado à interface de Alvo public class Tomada3Pinos{ public void ligarTomada3Pinos(){ System.out.println(“Tomada de 3 ligada”) } } public class Cliente { public static void main(String args[]) { Tomada3Pinos tomada = new Tomada3Pinos(); t3.ligarTomada3pinos(); } } public class Tomada2Pinos{ public void ligarTomada2Pinos(){ System.out.println(“Tomada de 2 ligada”) } } Nova classe que precisa ser adaptada ao sistema. Alvo public class Tomada3Pinos{ public void ligarTomada3Pinos(){ System.out.println(“Tomada de 3 ligada”) } } public class Tomada2Pinos{ public void ligarTomada2Pinos(){ System.out.println(“Tomada de 3 ligada”) } } Adaptado public class Tomada2PinosAdapter extends Tomada3Pinos { private Tomado2Pinos t2Pinos; public Tomado2PinosAdapter(Tomada2Pinos t2Pinos) { this.t2Pinos = t2Pinos; } public void ligarTomada3Pinos() { t2Pinos.ligarTomada2Pinos(); } } public class Teste { public static void main(String args[]) { Tomada2PinosAdapter t2 = new Tomada2PinosAdapter(new Tomada2Pinos()); t2.ligarTomada3pinos(); } } Exemplo 2: Imaginem que a aplicação do cliente possui uma classe (PrintRelatorio) para impressão de relatórios; implementada inicialmente para impressão somente no console; Possui um objeto do tipo PrintStream chamado out; Possui um método chamado imprime que recebe a string a ser impressa. public class PrintRelatorio { private PrintStream out; public PrintStream getOut(){ return this.out; } public void setOut(PrintStream out) { this.out = out; } public void imprime(String texto){ getOut().print (texto); } } Utilizando a classe PrintRelatorio public static void main(String[] args) { PrintRelatorio relatorio = new PrintRelatorio(); relatorio.setOut(System.out); relatorio.imprime("texto"); } O problema é que agora o cliente precisa de uma impressão mais elaborada em uma caixa de mensagens (JOptionPane); A classe PrintRelatorio já esta homologada em execução; Precisamos usar JOptionPane.showMessageDialog() no lugar de System.out.print (); E ainda é necessário chamar relatorio.setOut(JOptionPane), mas esse método recebe algo do tipo PrintStream; Como contornar esse conjunto de problemas? Criamos uma nova classe AdaptadoraParaPainel: Estendemos PrintStream; Somos então obrigados a inserir um construtor para informar um Arquivo, visto que a especialidade dela é trabalhar com streams. Mas não vamos trabalhar com arquivos! Então inserimos o construtor que ela espera, declarar a exceção que ela espera, apenas para compilador parar de reclamar. public class AdaptadoraParaPainel extends PrintStream{ public AdaptadoraParaPainel() throws FileNotFoundException{ super(new File(“”)); } @overhide public void print(String texto){ JOptionPane.showMessageDialog(null,texto); } } Assim a classe cliente continua invocando o método setOut() que espera um PrintStream: public class Cliente { public static void main(String[] args) throws FileNotFoundException { PrintRelatorio relatorio = new PrintRelatorio(); relatorio.setOut(new AdaptadoraParaPainel()); relatorio.imprime("texto"); } } Quando queremos usar uma classe já pronta, mas que possui uma interface diferente da que precisamos; Como exemplos no próprio Java temos: Classes envoltório: Integer Boolean Float Adaptadores de evento(AWT/SWING) Java.awt.MouseAdapter adapta java.awt.MouseListener a uma interface mais simples Facade Objetivo: Ocultar a complexidade de uma ou mais classes através de uma “fachada”: Simplificar a utilização de um subsistema Encapsular as interfaces, fornecendo uma simplificada para acessar as principais funcionalidades do subsistema Problema: Considere que que em um sistema existem várias classes, as quais possuem diversos métodos: As principais funcionalidades do sistema provêm de alguns métodos dessas classes A comunicação do sistema com as várias classes gera alto acoplamento Solução: Criar uma classe (“fachada”) que mantém a interação com o subsistema de classes, e fornece uma interface mais simples para o sistema Essa seria uma interface de mais alto nível Considere: Sistema multimídia Sistema de vídeo (SistemaDeVideo) configurarResolucao configurarCores renderizarImagem Sistema de áudio (SistemaDeAudio) configurarFrequencia configurarVolume configurarCanais reproduzirAudio Sistema de entrada de dados (SistemaDeInput) configurarTeclado configurarJoystick lerInput Resumo: Simplifica uma interface unificando um conjunto de classes mais complexas que fazem parte de um subsistema Permite desconectar a implementação do sistema principal de qualquer subsistema de classes Um sistema pode ter várias “fachadas” integradas Versus Adapter: O padrão Adapter tem por objetivo alterar uma interface para torná-la compatível com o sistema (Converter) O padrão Facade visa fornecer uma interface unificada/simplificada para um subsistema (Unificar)
Compartilhar