Baixe o app para aproveitar ainda mais
Prévia do material em texto
Revisão Av1 Padrões de Projeto De Software Visão geral da Programação OO A OO tem evoluído muito, principalmente em questões voltadas para segurança e reaproveitamento de código. A Programação Orientada a Objetos (POO) diz respeito a uma abordagem de desenvolvimento que é seguido por muitas linguagens, como Java C#. Visão geral da Programação OO A ideia fundamental da POO é representação de cada elemento em termos de um objeto, ou classe. Esta representação traz vantagens: •A reutilização de código é um dos principais requisitos no desenvolvimento de software atual. •A POO esta baseada nos conceitos de: •Abstração •Encapsulamento •Herança •Polimorfismo Princípios da POO com Java O Java implementa os conceitos de Abstração, Encapsulamento, Herança e polimorfismo de forma bastante intuitiva, o que facilita o entendimento no desenvolvimento de software. A abstração é implementada através de classes, que contém propriedades e métodos, de forma bastante simples. É utilizada para a definição de entidades do mundo real como classes. O encapsulamento é realizado através de propriedades privadas, auxiliadas por métodos especiais getters e setters. É a técnica utilizada para esconder uma ideia, ou seja, não expor detalhes internos para o usuário, tornando partes do sistema mais independentes possível. O Java possui herança simples, o que significa que cada classe pode herdar de apenas uma outra. Entretanto, o Java possui as chamadas Interfaces, que possuem propriedades e assinaturas de métodos. No polimorfismo, o atributo @Override é responsável por informar ao Java que o método em questão está sendo reescrito. Controle e tratamento de exceções Exceção: uma indicação de um problema que ocorre durante a execução de um programa. Usar tratamento de exceções permite detectar erros e manipular esses erros. O tratamento de exceções resolve exceções que poderiam ocorrer para que o programa continue ou termine elegantemente. O tratamento de exceções permite que os programadores criem programas mais robustos e tolerantes a falhas. try - é usada para indicar um bloco de código que possa ocorrer uma exceção. catch - serve para manipular as exceções, ou seja, tratar o erro. finally - sempre será executado depois do bloco try/catch. Throws - especifica as exceções que um método pode lançar. O importante é saber que esse bloco sempre será executado (exceto nos casos de encerramento da jvm System.exit()). ArrayIndexOutOfBoundsException: é feita uma tentativa de acessar um elemento depois do final de um array. ClassCastException: ocorre uma tentativa de fazer uma coerção em um objeto que não tem um relacionamento é um com o tipo especificado no operador de coerção. NullPointerException: quando uma referência null é utilizada onde um objeto é esperado. Bloco try contém o código que pode lançar (throw) uma exceção. • Consiste na palavra- chave try seguida por um bloco de código entre chaves. • Se ocorrer uma exceção em algum ponto, o restante do código contido no bloco try não será executado. Um bloco catch: Captura, isto é, recebe e trata uma exceção. Começa com a palavra-chave catch. Parâmetro de exceção entre parênteses, o parâmetro de exceção identifica o tipo de exceção e permite que o bloco catch interaja com o objeto da exceção capturada. Bloco do código entre chaves que executa quando uma exceção do tipo adequado ocorre. Bloco catch correspondente: o tipo do parâmetro de exceção corresponde exatamente ao tipo de exceção lançado ou é uma superclasse dele. • Exceção não-capturada: uma exceção que ocorre para a qual não há nenhum bloco catch correspondente. Faz com que o programa termine se o programa tiver somente um thread; do contrário apenas o thread atual é terminado e pode haver efeitos adversos no restante do programa. Modelo de terminação de tratamento de exceções: Quando uma exceção ocorre: O bloco try termina imediatamente. O programa transfere o controle para o primeiro bloco catch correspondente. Depois de a exceção ser tratada: Modelo de terminação do tratamento de exceções o controle do programa não retorna ao ponto de lançamento porque o bloco catch terminou; o fluxo de controle prossegue para a primeira instrução depois do último bloco catch. Usado pelo Java. Modelo de retomada do tratamento de exceções: o controle do programa é retomado logo depois do ponto de lançamento. Usado por algumas outras linguagens Utilizando a cláusula throws Cláusula throws: especifica as exceções que um método pode lançar: Aparece depois da lista de parâmetros do método e antes do corpo do método. Contém uma lista separada por vírgulas das exceções. As exceções podem ser lançadas pelas instruções no corpo do método ou pelos métodos chamados no corpo do método. As exceções podem ser dos tipos listados na cláusula throws ou subclasses. Quando utilizar o tratamento de exceções: O tratamento de exceções foi concebido para processar erros síncronos. Erros síncronos: ocorrem quando uma instrução executa. Erros assíncronos: ocorrem em paralelo e independente do fluxo de controle do programa. Programas que obtêm certos recursos devem retorná-los ao sistema explicitamente para evitar vazamentos de recursos. Bloco finally: Consiste na palavra-chave finally seguida por um bloco do código entre chaves. Opcional em uma instrução try. Se presente, é colocado depois do último bloco catch. Executa se uma exceção for lançada no bloco try correspondente ou qualquer um dos seus blocos catch correspondentes. Não executará se a aplicação encerrar prematuramente em um bloco try via o método System.exit. Em geral, contém código de liberação de recursos.. FUNDAMENTOS DE PADRÕES DE PROJETO DE SOFTWARE O que é um padrão? Um PADRÃO é uma descrição nomeada de um problema e uma solução que pode ser aplicado em novos contextos. Muitos padrões fornecem orientação sobre a atribuição de responsabilidades a objetos, dada uma categoria específica de problemas. A UML define responsabilidade como um contrato. As responsabilidades estão relacionadas com as obrigações de um objeto em termos de comportamento. As responsabilidades podem ser de dois tipos: Conhecer: Ter conhecimento sobre dados privados encapsulados. Conhecer objetos relacionados. Conhecer coisas que ele poder derivar ou calcular. •Fazer: Criar um objeto ou executar um cálculo. Iniciar uma ação em outro objeto. Controlar e coordenar atividades em outros objetos. Benefícios Aprendizagem com a experiência dos outros Identificação de problemas comuns de projeto de software Utilização de soluções testadas e bem documentadas Ajuda um novato a agir mais como um experiente Produção de bons projetos orientados a objetos Normalmente utilizam boas práticas de OO Utilizam eficientemente polimorfismo, herança e composição Vocabulário comum Uso de soluções que têm nome facilita comunicação Nível mais alto de abstração Ajuda na documentação Uso de soluções que têm um nome facilita a documentação Conhecimento de padrões de projeto torna mais fácil a compreensão de sistemas existentes Ajuda na conversão de um modelo de análise em um modelo de implementação Aumento da produtividade Como descrever (Elementos essenciais): Nome: Procura descrevero problema, a solução e as consequências em uma ou duas palavras. Problema: Quando aplicar o padrão e em que condições Sumário: Descreve os passos até a solução geral Solução: Descreve os elementos do padrão, seus relacionamentos, responsabilidades e colaborações. Consequências: Apresenta os resultados e a análise das vantagens e desvantagens da aplicação do padrão. Custos e benefícios de se aplicar o padrão. Padrões Relacionados. Informar uma listagem de padrões relacionados. Principais padrões de Projeto: Padrões de criação (Creational Patterns) Padrões de Estrura (Structural Patterns) Padrões de Comportamento (Behavioral Patterns) Padrões de Divisão Padrões de Concorrência Padrões GRASP Padrões para design de Interfaces (GUI) Padrões para organização de códigos Padrões para otimização Padrões de Robustez de código Padrões de testes Padrões GoF (Gang of Four) Não apresenta padrão para um domínio de aplicação específico Padrões do GoF representam o estado-da-prática em boas construções de projeto orientado a objetos É comum encontrar no detalhamento de padrões específicos de domínio a ocorrência de algum dos padrões do GoF Classificação dos Padrões (GOF) Os padrões são classificados em três tipos): Criacionais (5) Estruturais (7) Comportamentais (11) Divididos em 2 escopos: Classe: Relacionamentos entre classes e suas subclasses Não é preciso executar nenhum código para determinar o uso dos padrões Estáticos: fixos em tempo de compilação Classificação dos Padrões GOF-Escopo Objeto: Confia em ponteiros de objetos Dinâmicos: relacionamentos entre objetos podem ser alterados em tempo de execução. Padrões de Criação 1.Abstract Factory 2.Builder 3.Factory Method 4.Prototype 5.Singleton Padrões Estruturais 6.Adapter 7.Bridge 8.Composite 9.Decorator 10.Facade 11.Flyweight 12.Proxy Padrões de comportamento 13.Chain of Responsibility 14.Command 15.Interpreter 16.Iterator 17.Mediator 18.Memento 19.Observer 20.State 21.Strategy 22.Template Method 23.Visitor Classificação dos Padrões GOF Criacionais: Associados ao processo de criação de objetos Tornam um sistema independente de como seus objetos são criados, compostos e representados Estruturais Tratam de compor classes e objetos para formar estruturas grandes e complexas Associados à maneira como classes e objetos são organizados estruturalmente Oferecem formas efetivas para usar conceitos OO como herança, agregação e composição Focam na abstração da estrutura Comportamentais: Tratam de algoritmos e como atribuir responsabilidades entre objetos Associados à maneira que objetos e classes distribuem suas responsabilidades para realizar uma tarefa Focam na abstração do comportamento Padrões de Projetos do POSA Padrões Arquiteturais Padrões de Projeto Idiomas Padrões Arquiteturais Expressam um esquema de organização estrutural para sistemas de software Oferecem um conjunto de subsistemas pré-definidos, especifica suas respectivas responsabilidades e inclui regras e diretrizes para organizar as relações entre eles Exemplos MVC Broker Layer Reflection Padrões de Projeto Oferece um esquema para refinar os subsistemas ou componentes de um sistema de software ou as relações entre eles. •São considerados padrões de média escala •Exemplos Idiomas Padrão de baixo nível específico de uma linguagem de programação •Mostra como se pode implementar um dado componente/classe ou interação entre componentes/classes usando os recursos de uma LP •Exemplos •Singleton em C++ ou em Java •Counted Pointer: gerência de memória em C++ Padrão MVC(Model-View-Controller) MVC: Um dos padrões mais conhecidos para interação com o usuário Divide a aplicação em três partes fundamentais: Model – Representa os dados da aplicação e as regras de negócio View – Representa a interpretação visual do modelo pelo usuário Controller - Responsável por mediar a interação usuário-aplicação O padrão foi originalmente criado em 1978 Desde então diversas variações foram criadas para acompanhar novas demandas na iteração com o usuário (UI). Padrão MVC original Responsabilidades: Controller: Recebe dados de Usuário (ex.: teclado) e possui lógica de apresentação View: mostra projeções (saída) sobre os dados do modelo Model: representação dos dados e regras de negócios Interação (em camadas) no MVC Descrição: 1.O usuário faz requisições por dados ou ações sobre os dados do modelo ao Controller. 2.O Controller recebe as requisições e repassa para o objeto apropriado do Model para atendê-la. 3.O Model faz as operações sobre os dados e retorna algum tipo de informação ao Controller, que por sua vez devolve informações para objetos na camada de apresentação. 4.Atualizações no Model são avisadas ao View. Padrões de criação Abstraem o processo de instanciação Tornam um sistema independente da forma como os objetos são criados, compostos e representados. Padrões Criacionais (5) 1. Abstract Factory 2. Builder 3. Factory Method 4. Prototype 5. Singleton 1. Abstract Factory (Fábrica Abstrata) Objetivo: prover uma interface para criação de famílias de objetos relacionados sem especificar sua classe concreta. Motivação: Considere uma aplicação com interface gráfica que é implementada para plataformas diferentes (Motif para UNIX e outros ambientes para Windows e MacOS). 1. Abstract Factory - Motivação As classes que implementam os elementos gráficos não podem ser definidas estaticamente no código. Precisamos de uma implementação diferente para cada ambiente. Até em um mesmo ambiente, gostaríamos de dar a opção ao usuário de implementar diferentes aparências (look-and-feels). •Podemos solucionar este problema definindo uma classe abstrata para cada elemento gráfico e utilizando diferentes implementações para cada aparência ou para cada ambiente. Ao invés de criarmos as classes concretas com o operador new, utilizamos uma Fábrica Abstrata para criar os objetos em tempo de execução. O código cliente não sabe qual classe concreta utilizamos. 1. Abstract Factory Use uma fábrica abstrata quando: O sistema precisa ser independente de como os produtos são criados, compostos e representados. O sistema deve ser configurado com uma de múltiplas famílias de produtos. Produtos de uma família devem ser sempre utilizados em conjunto e isto precisa ser garantido. Deseja-se disponibilizar uma biblioteca de classes de produtos, mas revelar somente as suas interfaces, não suas implementações. 2. Builder Objetivo: 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. Mover a lógica de construção de uma classe para um objeto externo, a fim de reduzir a complexidade da mesma e permitir a construção gradual de objetos-alvo a partirdessa classe. Motivação: Suponha que se deseje converter documentos RTF para outros formatos (texto, HTML, ...) Seria necessário verificar quais partes um documento pode ter e definir uma especialização para cada uma das partes Builder (quando usar) Aplicabilidade: 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. 3. Factory Method Objetivo: Definir uma interface de criação de objetos mas deixar as subclasses decidirem qual objeto criar Motivação: Na construção de frameworks, não é possível, a priori, determinar qual elemento deve ser criado. A solução é permitir que o instanciador do framework faça a criação de uma instância específica Aplicabilidade: Sugestões para o uso desse padrão (GAMMA, HELM, et al., 2000): Quando uma classe não pode antecipar ou conhecer a classe dos objetos que deve criar; Quando uma classe quer suas subclasses para especificar os objetos que cria; Quando classes delegam responsabilidade à alguma das várias subclasses ajudantes, e deseja-se localizar qual é a subclasse ajudante acessada. 4. Prototype Objetivo: Especificar tipos de objetos a serem criados usando protótipos e aplicando clonagem nesses protótipos Motivação: Existem situações onde é desejável utilizar um objeto modelo complexo para a criação de outros objetos Supondo o caso de uma ferramenta de desenho, pode ser útil criar estruturas complexas e fazer uso delas como base para outros desenhos mais complexos Aplicabilidade: O padrão Prototype pode ser utilizado em sistemas que precisam ser independentes da forma como os seus componentes são criados, compostos e representados. O padrão Prototype pode ser útil em sistemas com as seguintes características: Sistemas que utilizam classes definidas em tempo de execução; Sistemas que utilizam o padrão Abstract Factory para criação de objetos. Neste caso, a hierarquia de classes pode se tornar muito complexa e o padrão Prototype pode ser uma alternativa mais simples, por realizar a mesma tarefa com um número reduzido de classes; 5. Singleton Objetivo: Assegurar que uma determinada classe tem somente uma única instância e fornecer um ponto global de acesso a ela Motivação: Garantir que exista um determinado número X de objetos de uma classe Independentemente do número de requisições que receber para criá-lo Exemplos de aplicação Único banco de dados Único acesso ao arquivo de log Única fachada (padrão Façade) Propósito Assegurar o controle da quantidade de instâncias da classe Ponto de acesso global a ela Aplicabilidade Exatamente uma instância da classe Acessível pelos clientes de ponto de acesso bem conhecido Instância única deve ser extensível através de subclasses Clientes capazes de usar instância estendida sem alterar seu código Participantes Singleton Define operação Instance que permite que clientes acessem instância única Instance é operação de classe Pode ser responsável pela criação de sua única instância Consequências Acesso controlado a instância única Espaço de nomes reduzido Refinamento de operações e representação Não há número variado de instâncias Mais flexível do que operações de classes 5. Singleton Exemplo: Padrões Estruturais 6.Adapter 7.Bridge 8.Composite 9.Decorator 10.Façade 11.Flyweight 12.Proxy 6. Adapter Objetivo: Converter a interface de uma classe em outra interface esperada pelos clientes. Permitir a comunicação entre classes que não poderiam trabalhar juntas devido à incompatibilidade de suas interfaces. •Estrutura: Cliente: aplicação que colabora com objetos que implementam Alvo •Alvo: define a interface requerida pelo Cliente •ClasseExistente: classe dos objetos que requerem adaptação •Adaptador: adapta a interface do Recurso à interface Alvo Quando usar: Aplicabilidade Use o Padrão Adapter quando: Deseja-se usar uma classe existente, e sua interface não é compatível com uma que se necessita Deseja-se criar uma classe reusável que coopera com classes não-relacionadas ou não previstas a priori, isto é, classes que não apresentam necessariamente interfaces compatíveis (Somente para ObjectAdapter) precisa-se usar várias subclasses existentes (de Adaptee), mas é impraticável adaptar as interfaces de cada uma através de herança. Um ObjectAdapter pode resolver isto adaptando abstratamente a interface da superclasse. 6. Bridge Objetivo: Desacoplar a abstração da sua implementação, de modo que as duas possam variar independentemente . 7. Bridge Objetivo: •Desacoplar a abstração da sua implementação, de modo que as duas possam variar independentemente Motivação Quando uma abstração pode ter várias implementações a solução usual é acomodar todas as implementações através de herança No entanto, herança liga de forma permanente uma abstração a uma implementação O padrão Bridge permite colocar as abstrações e suas implementações em diferentes hierarquias de classes, e permite que variem de forma independente Aplicabilidade: Use o Padrão Bridge Quando: Você quer evitar ligação permanente entre uma abstração e sua implementação. Pode ser, por exemplo, quando se deseja variar a implementação em run-time Tanto a abstração quanto a implementação devem ser extensíveis através de herança Mudanças na implementação de uma abstração não devem ter impacto sobre o cliente 8. Composite Objetivo: Compor objetos em estruturas de árvore para representar hierarquias todo-parte. Composite permite que clientes tratem objetos individuais e composições de objetos de maneira uniforme. Problema Cliente precisa tratar de maneira uniforme objetos individuais e composições desses objetos Solução Tratar grupos e indivíduos diferentes através de uma única interface Quando usar: Aplicabilidade quando se quer hierarquias de objetos que se relacionam como parte/todo quando se quer que “clientes” ignorem a diferença entre composição de objetos e objetos individuais 9. Decorator Objetivo Anexa dinamicamente responsabilidades adicionais a um objeto. Provê uma alternativa flexível ao uso de herança como modo de estender funcionalidade Motivação Algumas vezes se quer adicionar responsabilidades a um objeto, mas não à sua classe. Acontece, por exemplo, com a criação de interfaces gráficas, quando se deseja acrescentar uma borda a um componente qualquer ou um scrollbara uma área de texto. Uma forma de se acrescentar responsabilidades é através de herança, mas isto torna o projeto inflexível, pois a escolha da borda é definida em tempo de compilação. Neste caso o cliente não pode controlar como, onde e quando decorar o componente com uma borda. Uma abordagem mais flexível é inserir o componente em outro objeto que adiciona a borda, um Decorator. Aplicabilidade: Use o padrão Decorator: Para adicionar responsabilidades a objetos individuais de forma dinâmica e transparente, sem afetar outros objetos Para responsabilidades que podem ser removidas Quando extensão através de herança é impraticável. Algumas vezes uma grande quantidade de extensões independentes são possíveis e seria necessário um imenso número de subclasses para suportar cada combinação possível entre elas. Consequências: Mais flexibilidade que herança Evita incorporação forçada de comportamentos desnecessários 10. Façade Objetivo: Prover uma interface unificada para o conjunto de interfaces de um subsistema. Define uma interface de alto nível que faz um subsistema mais fácil de usar. Motivação: Estruturar um sistema em subsistemas contribui para reduzir sua complexidade. A dependência entre subsistemas pode ser minimizada através do uso de um objeto Fachada, o qual provê uma interface única e uniforme para as diversas funcionalidades de um subsistema. Aplicabilidade: Use o Padrão Façade quando: Você quer prover uma interface simplificada para um subsistema complexo. Um Façade pode prover uma visão simples do subsistema, suficiente para a maioria dos clientes Existem muitas dependências entre clientes e classes da implementação. O Façade reduz esta dependência e promove independência e portabilidade Você quer criar sistemas em camadas. Um Façade provê o ponto de entrada para cada camada (nível) do subsistema. Consequências: Promove acoplamento fraco entre o subsistema e seus clientes No entanto, não evita que aplicações possam acessar diretamente as subclasses do sistema, se assim o desejarem. 11. Flyweight Objetivo: Usar compartilhamento para suportar eficientemente grandes quantidades de objetos de granularidade fina. Motivação: Aplicações que utilizam grande número de objetos Exemplo de Problema: desenvolver um editor de texto onde cada caracter é representado por um objeto. Pode não haver recursos (memória) sufientes para textos muito grandes. Motivação: Aplicações que utilizam grande número de objetos Exemplo de solução: monta-se um pool de objetos compartilhados. Cada caracter tem um objeto. Com 100 objetos (tabela ASCII) poderíamos montar textos de qualquer tamanho Aplicabilidade: Aplicação utiliza grande número de objetos Custos de armazenamento altos A maior parte dos estados de objetos pode ser tornada extrínseca (estados externalizados) Muitos objetos podem ser substituídos por poucos objetos compartilhados Aplicação não depende da identidade dos objetos. obs: testes de identidade produzirão o valor verdadeiro para objetos conceitualmente distintos. 12. Proxy Objetivo: Disponibilizar um substituto para outro objeto, controlando o acesso a ele. Motivação: Várias razões para controlar acesso a um objeto, como por exemplo: deferir o custo de criação e inicialização para o momento de uso (objetos sob demanda); Prover um representante local para um objeto remoto; Proteger o objeto original. Problema Aplicabilidade O Padrão Proxy é usado sempre que se precisa de uma referência a um objeto, que seja mais versátil ou sofisticada do que um simples ponteiro. As principais situações são: Remote Proxy: provê um representante local para um objeto em um espaço de endereçamento diferente Virtual Proxy: cria objeto sob demanda Protection Proxy: controla acesso ao objeto original Smart References: executa operações adicionais quando o objeto é acessado Contagem de referências, carga de objetos persistentes, locks Copy-on-write: compartilhar grandes objetos, fazendo uma cópia apenas se necessário
Compartilhar